You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/02/24 17:31:54 UTC

[01/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.0.0 828d85ddd -> f5482d89d


http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/udfs/UDFServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/udfs/UDFServiceTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/udfs/UDFServiceTest.java
new file mode 100644
index 0000000..9271e97
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/udfs/UDFServiceTest.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.udfs;
+
+import org.apache.ambari.view.hive.BaseHiveTest;
+import org.apache.ambari.view.hive.resources.udfs.UDF;
+import org.apache.ambari.view.hive.resources.udfs.UDFService;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.json.simple.JSONObject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+import static org.easymock.EasyMock.*;
+
+public class UDFServiceTest extends BaseHiveTest {
+  @Rule public ExpectedException thrown = ExpectedException.none();
+  private UDFService udfService;
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    udfService = getService(UDFService.class, handler, context);
+  }
+
+  private Response doCreateUDF() {
+    UDFService.UDFRequest request = new UDFService.UDFRequest();
+    request.udf = new UDF();
+    request.udf.setClassname("/tmp/udf.jar");
+    request.udf.setName("TestUDF");
+
+    UriInfo uriInfo = createNiceMock(UriInfo.class);
+    URI uri = UriBuilder.fromUri("http://host/a/b").build();
+    expect(uriInfo.getAbsolutePath()).andReturn(uri);
+
+    HttpServletResponse resp_obj = createNiceMock(HttpServletResponse.class);
+
+    resp_obj.setHeader(eq("Location"), anyString());
+
+    replay(uriInfo, resp_obj);
+    return udfService.create(request, resp_obj, uriInfo);
+  }
+
+  @Test
+  public void createUDF() {
+    Response response = doCreateUDF();
+    Assert.assertEquals(201, response.getStatus());
+
+    JSONObject obj = (JSONObject)response.getEntity();
+    Assert.assertTrue(obj.containsKey("udf"));
+    Assert.assertNotNull(((UDF) obj.get("udf")).getId());
+    Assert.assertFalse(((UDF) obj.get("udf")).getId() == null);
+  }
+
+  @Test
+  public void udfNotFound() {
+    thrown.expect(NotFoundFormattedException.class);
+    udfService.getOne("4242");
+  }
+
+  @Test
+  public void updateUDF() {
+    Response createdUDF = doCreateUDF();
+    Integer createdUdfId = ((UDF) ((JSONObject) createdUDF.getEntity()).get("udf")).getId();
+
+    UDFService.UDFRequest request = new UDFService.UDFRequest();
+    request.udf = new UDF();
+    request.udf.setClassname("/tmp/updatedUDF.jar");
+    request.udf.setName("TestUDF2");
+
+    Response response = udfService.update(request, String.valueOf(createdUdfId));
+    Assert.assertEquals(204, response.getStatus());
+
+    Response response2 = udfService.getOne(String.valueOf(createdUdfId));
+    Assert.assertEquals(200, response2.getStatus());
+
+    JSONObject obj = ((JSONObject) response2.getEntity());
+    Assert.assertTrue(obj.containsKey("udf"));
+    Assert.assertEquals(((UDF) obj.get("udf")).getName(), request.udf.getName());
+    Assert.assertEquals(((UDF) obj.get("udf")).getClassname(), request.udf.getClassname());
+  }
+
+  @Test
+  public void deleteUDF() {
+    Response createdUDF = doCreateUDF();
+    Integer createdUdfId = ((UDF) ((JSONObject) createdUDF.getEntity()).get("udf")).getId();
+
+    Response response = udfService.delete(String.valueOf(createdUdfId));
+    Assert.assertEquals(204, response.getStatus());
+
+    thrown.expect(NotFoundFormattedException.class);
+    udfService.getOne(String.valueOf(createdUdfId));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/HdfsApiMock.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/HdfsApiMock.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/HdfsApiMock.java
new file mode 100644
index 0000000..bb922e2
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/HdfsApiMock.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.hive.utils;
+
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import static org.easymock.EasyMock.*;
+
+/**
+* Created by roma on 2/6/15.
+*/
+public class HdfsApiMock {
+  private ByteArrayOutputStream fsQueryOutputStream;
+  private ByteArrayOutputStream fsLogsOutputStream;
+  private HdfsApi hdfsApi;
+
+  public HdfsApiMock(String inputFileContent) throws IOException, InterruptedException {
+    setupHdfsApi(inputFileContent);
+  }
+
+  protected void setupHdfsApi(String inputFileContent) throws IOException, InterruptedException {
+    hdfsApi = createNiceMock(HdfsApi.class);
+
+    hdfsApi.copy(anyString(), anyString());
+
+    fsQueryOutputStream = setupQueryOutputStream(hdfsApi);
+    fsLogsOutputStream = setupLogsOutputStream(hdfsApi);
+    setupQueryInputStream(hdfsApi, inputFileContent);
+
+    expect(hdfsApi.mkdir(anyString())).andReturn(true).anyTimes();
+  }
+
+  protected SeekableByteArrayInputStream setupQueryInputStream(HdfsApi hdfsApi, String query) throws IOException, InterruptedException {
+    SeekableByteArrayInputStream inputStreamHQL = new SeekableByteArrayInputStream(query.getBytes());
+    expect(hdfsApi.open(endsWith(".hql"))).andReturn(new FSDataInputStream(inputStreamHQL)).anyTimes();
+    return inputStreamHQL;
+  }
+
+  protected ByteArrayOutputStream setupQueryOutputStream(HdfsApi hdfsApi) throws IOException, InterruptedException {
+    ByteArrayOutputStream queryOutputStream = new ByteArrayOutputStream();
+    FSDataOutputStream fsQueryOutputStream = new FSDataOutputStream(queryOutputStream);
+    expect(hdfsApi.create(endsWith(".hql"), anyBoolean())).andReturn(fsQueryOutputStream);
+    return queryOutputStream;
+  }
+
+  protected ByteArrayOutputStream setupLogsOutputStream(HdfsApi hdfsApi) throws IOException, InterruptedException {
+    ByteArrayOutputStream logsOutputStream = new ByteArrayOutputStream();
+    FSDataOutputStream fsLogsOutputStream = new FSDataOutputStream(logsOutputStream);
+    expect(hdfsApi.create(endsWith("logs"), anyBoolean())).andReturn(fsLogsOutputStream).anyTimes();
+    return logsOutputStream;
+  }
+
+  public HdfsApi getHdfsApi() {
+    return hdfsApi;
+  }
+
+  public ByteArrayOutputStream getQueryOutputStream() {
+    return fsQueryOutputStream;
+  }
+
+  public ByteArrayOutputStream getLogsOutputStream() {
+    return fsLogsOutputStream;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/SeekableByteArrayInputStream.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/SeekableByteArrayInputStream.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/SeekableByteArrayInputStream.java
new file mode 100644
index 0000000..332dc5d
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/utils/SeekableByteArrayInputStream.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.hive.utils;
+
+import org.apache.hadoop.fs.PositionedReadable;
+import org.apache.hadoop.fs.Seekable;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+* Created by roma on 2/6/15.
+*/
+public class SeekableByteArrayInputStream extends ByteArrayInputStream
+    implements Seekable, PositionedReadable {
+  public SeekableByteArrayInputStream(byte[] buf) {
+    super(buf);
+  }
+
+  public SeekableByteArrayInputStream(byte buf[], int offset, int length) {
+    super(buf, offset, length);
+    throw new UnsupportedOperationException("Seek code assumes offset is zero");
+  }
+
+  public void seek(long position) {
+    if (position < 0 || position >= buf.length)
+      throw new IllegalArgumentException("pos = " + position + " buf.lenght = " + buf.length);
+    this.pos = (int) position;
+  }
+
+  public long getPos() {
+    return this.pos;
+  }
+
+  @Override
+  public boolean seekToNewSource(long l) throws IOException {
+    throw new UnsupportedOperationException("seekToNewSource is not supported");
+  }
+
+  @Override
+  public int read(long l, byte[] buffer, int offset, int length) throws IOException {
+    this.seek(l);
+    return this.read(buffer, offset, length);
+  }
+
+  @Override
+  public void readFully(long l, byte[] bytes, int i, int i1) throws IOException {
+    throw new UnsupportedOperationException("readFully is not supported");
+  }
+
+  @Override
+  public void readFully(long l, byte[] bytes) throws IOException {
+    throw new UnsupportedOperationException("readFully is not supported");
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/pom.xml b/contrib/views/pom.xml
index 608a8b0..60c3b71 100644
--- a/contrib/views/pom.xml
+++ b/contrib/views/pom.xml
@@ -38,6 +38,7 @@
     <module>pig</module>
     <module>slider</module>
     <module>capacity-scheduler</module>
+    <module>hive</module>
     <module>tez</module>
   </modules>
   <build>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 3436450..9fc2c90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -299,6 +299,7 @@
             <exclude>contrib/ambari-scom/*/rat.txt</exclude>
             <exclude>contrib/ambari-scom/metrics-sink/target/**</exclude>
             <exclude>contrib/views/*/target/**</exclude>
+            <exclude>contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/**</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/bower_components/**</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/node/**</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/node_modules/**</exclude>


[11/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Row.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Row.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Row.java
new file mode 100644
index 0000000..306530a
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Row.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.hive.client;
+
+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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Utils.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Utils.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Utils.java
new file mode 100644
index 0000000..fd1ecb5
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Utils.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import org.apache.hive.service.cli.thrift.TStatus;
+import org.apache.hive.service.cli.thrift.TStatusCode;
+
+public class Utils {
+  static void verifySuccess(TStatus status, String comment) throws HiveClientException {
+    if (status.getStatusCode() != TStatusCode.SUCCESS_STATUS &&
+        status.getStatusCode() != TStatusCode.SUCCESS_WITH_INFO_STATUS) {
+      String message = (status.getErrorMessage() != null) ? status.getErrorMessage() : "";
+      throw new HiveErrorStatusException(status.getStatusCode(), message + ": " + comment);
+    }
+  }
+
+  public static class HiveAuthenticationParams {
+    public static final String AUTH_TYPE = "auth";
+    // We're deprecating this variable's name.
+    public static final String AUTH_QOP_DEPRECATED = "sasl.qop";
+    public static final String AUTH_QOP = "saslQop";
+    public static final String AUTH_SIMPLE = "noSasl";
+    public static final String AUTH_TOKEN = "delegationToken";
+    public static final String AUTH_USER = "user";
+    public static final String AUTH_PRINCIPAL = "principal";
+    public static final String AUTH_PASSWD = "password";
+    public static final String AUTH_KERBEROS_AUTH_TYPE = "kerberosAuthType";
+    public static final String AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT = "fromSubject";
+    public static final String ANONYMOUS_USER = "anonymous";
+    public static final String ANONYMOUS_PASSWD = "anonymous";
+    public static final String USE_SSL = "ssl";
+    public static final String SSL_TRUST_STORE = "sslTrustStore";
+    public static final String SSL_TRUST_STORE_PASSWORD = "trustStorePassword";
+    // We're deprecating the name and placement of this in the parsed map (from hive conf vars to
+    // hive session vars).
+    public static final String TRANSPORT_MODE_DEPRECATED = "hive.server2.transport.mode";
+    public static final String TRANSPORT_MODE = "transportMode";
+    // We're deprecating the name and placement of this in the parsed map (from hive conf vars to
+    // hive session vars).
+    public static final String HTTP_PATH_DEPRECATED = "hive.server2.thrift.http.path";
+    public static final String HTTP_PATH = "httpPath";
+    public static final String SERVICE_DISCOVERY_MODE = "serviceDiscoveryMode";
+    // Don't use dynamic service discovery
+    public static final String SERVICE_DISCOVERY_MODE_NONE = "none";
+    // Use ZooKeeper for indirection while using dynamic service discovery
+    public static final String SERVICE_DISCOVERY_MODE_ZOOKEEPER = "zooKeeper";
+    public static final String ZOOKEEPER_NAMESPACE = "zooKeeperNamespace";
+    // Default namespace value on ZooKeeper.
+    // This value is used if the param "zooKeeperNamespace" is not specified in the JDBC Uri.
+    public static final String ZOOKEEPER_DEFAULT_NAMESPACE = "hiveserver2";
+
+    // Non-configurable params:
+    // Currently supports JKS keystore format
+    public static final String SSL_TRUST_STORE_TYPE = "JKS";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ViewSessionState.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ViewSessionState.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ViewSessionState.java
new file mode 100644
index 0000000..aa6cd47
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ViewSessionState.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.hive.client;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.ql.session.SessionState;
+
+public class ViewSessionState extends SessionState {
+  public ViewSessionState(HiveConf conf) {
+    super(conf);
+  }
+
+  public ViewSessionState(HiveConf conf, String userName) {
+    super(conf, userName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/DataStoreStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/DataStoreStorage.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/DataStoreStorage.java
new file mode 100644
index 0000000..7a4ff40
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/DataStoreStorage.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.persistence;
+
+import org.apache.ambari.view.PersistenceException;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+import java.util.ArrayList;
+import java.util.Collections;
+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) {
+    try {
+      if (obj.getId() == null) {
+        int id = nextIdForEntity(context, model);
+        obj.setId(id);
+      }
+      context.getDataStore().store(obj);
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("Error while saving object to DataStorage", e);
+    }
+  }
+
+  private static synchronized int 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 newId;
+  }
+
+  @Override
+  public synchronized <T extends Indexed> T load(Class<T> model, Integer id) throws ItemNotFound {
+    LOG.debug(String.format("Loading %s #%d", 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("Error while finding object in DataStorage", 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, null)) {
+        if ((filter == null) || filter.isConform(item)) {
+          list.add(item);
+        }
+      }
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("Error while finding all objects in DataStorage", e);
+    }
+    return list;
+  }
+
+  @Override
+  public <T extends Indexed> List<T> loadWhere(Class<T> model, String where) {
+    LOG.debug(String.format("Loading all %s-s", model.getName()));
+    try {
+      return new ArrayList<T>(context.getDataStore().findAll(model, where));
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("Error while finding objects in DataStorage; where = " + where, e);
+    }
+  }
+
+  @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, int id) throws ItemNotFound {
+    LOG.debug(String.format("Deleting %s:%d", model.getName(), id));
+    Object obj = load(model, id);
+    try {
+      context.getDataStore().remove(obj);
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("Error while removing object from DataStorage", e);
+    }
+  }
+
+  @Override
+  public boolean exists(Class model, Integer id) {
+    try {
+      return context.getDataStore().find(model, id) != null;
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("Error while finding object in DataStorage", e);
+    }
+  }
+
+  public static void storageSmokeTest(ViewContext context) {
+    try {
+      SmokeTestEntity entity = new SmokeTestEntity();
+      entity.setData("42");
+      DataStoreStorage storage = new DataStoreStorage(context);
+      storage.store(SmokeTestEntity.class, entity);
+
+      if (entity.getId() == null) throw new ServiceFormattedException("Ambari Views instance data DB doesn't work properly (auto increment id doesn't work)", null);
+      Integer id = entity.getId();
+      SmokeTestEntity entity2 = storage.load(SmokeTestEntity.class, id);
+      boolean status = entity2.getData().compareTo("42") == 0;
+      storage.delete(SmokeTestEntity.class, id);
+      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);
+    }
+  }
+
+  public static class SmokeTestEntity implements Indexed {
+    private Integer id = null;
+    private String data = null;
+
+    public Integer getId() {
+      return id;
+    }
+
+    public void setId(Integer id) {
+      this.id = id;
+    }
+
+    public String getData() {
+      return data;
+    }
+
+    public void setData(String data) {
+      this.data = data;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/InstanceKeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/InstanceKeyValueStorage.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/InstanceKeyValueStorage.java
new file mode 100644
index 0000000..932b58e
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/InstanceKeyValueStorage.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.persistence;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.ContextConfigurationAdapter;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import javax.ws.rs.WebApplicationException;
+import java.util.List;
+
+
+/**
+ * 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);
+    }
+  }
+
+  @Override
+  public <T extends Indexed> List<T> loadWhere(Class<T> model, String where) {
+    throw new NotImplementedException();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/KeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/KeyValueStorage.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/KeyValueStorage.java
new file mode 100644
index 0000000..e8a904c
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/KeyValueStorage.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.hive.persistence;
+
+import com.google.gson.Gson;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.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(lastIndex);
+    }
+
+    String modelPropName = getItemPropertyName(model, obj.getId());
+    String json = serialize(obj);
+    write(modelPropName, json);
+  }
+
+  @Override
+  public <T extends Indexed> T load(Class<T> model, Integer 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, int id) {
+    LOG.debug(String.format("Deleting %s:%d", model.getName(), id));
+    String modelPropName = getItemPropertyName(model, id);
+    clear(modelPropName);
+  }
+
+  @Override
+  public boolean exists(Class model, Integer id) {
+    return getConfig().containsKey(getItemPropertyName(model, id));
+  }
+
+  private String getIndexPropertyName(Class model) {
+    return String.format("%s:index", model.getName());
+  }
+
+  private String getItemPropertyName(Class model, int id) {
+    return String.format("%s.%d", model.getName(), id);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/LocalKeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/LocalKeyValueStorage.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/LocalKeyValueStorage.java
new file mode 100644
index 0000000..674029a
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/LocalKeyValueStorage.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.hive.persistence;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.utils.MisconfigurationFormattedException;
+import org.apache.commons.configuration.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.util.List;
+
+
+/**
+ * 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;
+  }
+
+  @Override
+  public <T extends Indexed> List<T> loadWhere(Class<T> model, String where) {
+    throw new NotImplementedException();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/PersistentConfiguration.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/PersistentConfiguration.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/PersistentConfiguration.java
new file mode 100644
index 0000000..b8405ff
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/Storage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/Storage.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/Storage.java
new file mode 100644
index 0000000..fb75670
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/Storage.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.persistence;
+
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.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, Integer 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 where filtering strategy (where clause)
+   * @param <T> bean class
+   * @return list of filtered objects
+   */
+  <T extends Indexed> List<T> loadWhere(Class<T> model, String where);
+
+  /**
+   * 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, int id) throws ItemNotFound;
+
+  /**
+   * Check is object exists
+   * @param model bean class
+   * @param id identifier
+   * @return true if exists
+   */
+  boolean exists(Class model, Integer id);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ContextConfigurationAdapter.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ContextConfigurationAdapter.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ContextConfigurationAdapter.java
new file mode 100644
index 0000000..afc4c78
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/FilteringStrategy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/FilteringStrategy.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/FilteringStrategy.java
new file mode 100644
index 0000000..79aa2f9
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/FilteringStrategy.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.hive.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);
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ItemNotFound.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ItemNotFound.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/ItemNotFound.java
new file mode 100644
index 0000000..3b7e51a
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/OnlyOwnersFilteringStrategy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/OnlyOwnersFilteringStrategy.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/OnlyOwnersFilteringStrategy.java
new file mode 100644
index 0000000..9f2b4a2
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/OnlyOwnersFilteringStrategy.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.hive.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;
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/StorageUtil.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/StorageUtil.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/StorageUtil.java
new file mode 100644
index 0000000..1e67c02
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/persistence/utils/StorageUtil.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.hive.persistence.utils;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.DataStoreStorage;
+import org.apache.ambari.view.hive.persistence.LocalKeyValueStorage;
+import org.apache.ambari.view.hive.persistence.Storage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 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 StorageUtil {
+  private Storage storageInstance = null;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(StorageUtil.class);
+
+
+  private static Map<String, StorageUtil> viewSingletonObjects = new HashMap<String, StorageUtil>();
+  public static StorageUtil getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new StorageUtil(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public static void dropAllConnections() {
+    viewSingletonObjects.clear();
+  }
+
+  private ViewContext context;
+
+  /**
+   * Constructor of storage util
+   * @param context View Context instance
+   */
+  public StorageUtil(ViewContext context) {
+    this.context = context;
+  }
+
+  /**
+   * Get storage instance. If one is not created, creates instance.
+   * @return storage instance
+   */
+  public synchronized Storage getStorage() {
+    if (storageInstance == null) {
+      String fileName = context.getProperties().get("dataworker.storagePath");
+      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;
+  }
+
+  /**
+   * Set storage to use across all application.
+   * Used in unit tests.
+   * @param storage storage instance
+   */
+  public void setStorage(Storage storage) {
+    storageInstance = storage;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/CRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/CRUDResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/CRUDResourceManager.java
new file mode 100644
index 0000000..b8dec17
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/CRUDResourceManager.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.Storage;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.StorageUtil;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+
+import java.util.List;
+
+/**
+ * CRUD resource manager
+ * @param <T> Data type with ID
+ */
+abstract public class CRUDResourceManager<T extends Indexed> {
+  //TODO: refactor: generic parameter gets Fabric for Indexed objects, not objects itself
+  private Storage storage = null;
+
+  protected final Class<? extends T> resourceClass;
+
+  /**
+   * Constructor
+   * @param resourceClass model class
+   */
+  public CRUDResourceManager(Class<? extends T> resourceClass) {
+    this.resourceClass = resourceClass;
+  }
+  // CRUD operations
+
+  /**
+   * Create operation
+   * @param object object
+   * @return model object
+   */
+  protected T create(T object) {
+    object.setId(null);
+    return this.save(object);
+  }
+
+  /**
+   * Read operation
+   * @param id identifier
+   * @return model object
+   * @throws org.apache.ambari.view.hive.persistence.utils.ItemNotFound
+   */
+  protected T read(Integer id) throws ItemNotFound {
+    T object = null;
+    object = 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
+   */
+  protected List<T> readAll(FilteringStrategy filteringStrategy) {
+    return 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.hive.persistence.utils.ItemNotFound
+   */
+  protected T update(T newObject, Integer id) throws ItemNotFound {
+    newObject.setId(id);
+    this.save(newObject);
+    return newObject;
+  }
+
+  /**
+   * Delete operation
+   * @param resourceId object identifier
+   * @throws org.apache.ambari.view.hive.persistence.utils.ItemNotFound
+   */
+  protected void delete(Integer resourceId) throws ItemNotFound {
+    if (!getStorage().exists(this.resourceClass, resourceId)) {
+      throw new ItemNotFound();
+    }
+    getStorage().delete(this.resourceClass, resourceId);
+  }
+
+  // UTILS
+
+  protected T save(T object) {
+    getStorage().store(resourceClass, object);
+    return object;
+  }
+
+  protected Storage getStorage() {
+    if (storage == null) {
+      storage = StorageUtil.getInstance(getContext()).getStorage();
+    }
+    return storage;
+  }
+
+  protected abstract boolean checkPermissions(T object);
+  protected abstract ViewContext getContext();
+
+  protected void cleanupAfterErrorAndThrowAgain(Indexed object, ServiceFormattedException e) {
+    try {
+      delete(object.getId());
+    } catch (ItemNotFound itemNotFound) {
+      throw new ServiceFormattedException("Error in creation, during clean up: " + itemNotFound.toString(), itemNotFound);
+    }
+    throw e;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/PersonalCRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/PersonalCRUDResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/PersonalCRUDResourceManager.java
new file mode 100644
index 0000000..d1223fb
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/PersonalCRUDResourceManager.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.hive.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.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 ViewContext context;
+  protected boolean ignorePermissions = false;
+
+  private final static Logger LOG =
+      LoggerFactory.getLogger(PersonalCRUDResourceManager.class);
+  /**
+   * Constructor
+   * @param resourceClass model class
+   * @param context View Context instance
+   */
+  public PersonalCRUDResourceManager(Class<? extends T> resourceClass, ViewContext context) {
+    super(resourceClass);
+    this.context = context;
+  }
+
+  @Override
+  public T update(T newObject, Integer id) throws ItemNotFound {
+    T object = 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;
+  }
+
+  @Override
+  public ViewContext getContext() {
+    return context;
+  }
+
+  /**
+   * Execute action ignoring objects owner
+   * @param actions callable to execute
+   * @return value returned from actions
+   * @throws Exception
+   */
+  public <T> T ignorePermissions(Callable<T> actions) throws Exception {
+    ignorePermissions = true;
+    T result;
+    try {
+      result = actions.call();
+    } finally {
+      ignorePermissions = false;
+    }
+    return result;
+  }
+
+  protected static String getUsername(ViewContext context) {
+    String userName = context.getProperties().get("dataworker.username");
+    if (userName == null || userName.compareTo("null") == 0 || userName.compareTo("") == 0)
+      userName = context.getUsername();
+    return userName;
+  }
+
+  protected String getUsername() {
+    return getUsername(context);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/SharedCRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/SharedCRUDResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/SharedCRUDResourceManager.java
new file mode 100644
index 0000000..0d2b297
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/SharedCRUDResourceManager.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.hive.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.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
+   * @param context View Context instance
+   */
+  public SharedCRUDResourceManager(Class<T> responseClass, ViewContext context) {
+    super(responseClass);
+    this.context = context;
+  }
+
+  @Override
+  protected boolean checkPermissions(T object) {
+    return true; //everyone has permission
+  }
+
+  @Override
+  protected ViewContext getContext() {
+    return context;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
new file mode 100644
index 0000000..e5983b9
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
@@ -0,0 +1,263 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.browser;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.client.ColumnDescription;
+import org.apache.ambari.view.hive.client.ConnectionPool;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.resources.jobs.ResultsPaginationController;
+import org.apache.ambari.view.hive.utils.BadRequestFormattedException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.commons.collections4.map.PassiveExpiringMap;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+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);
+
+  private static final long EXPIRING_TIME = 10*60*1000;  // 10 minutes
+  private static Map<String, Cursor> resultsCache;
+  public static Map<String, Cursor> getResultsCache() {
+    if (resultsCache == null) {
+      PassiveExpiringMap<String, Cursor> resultsCacheExpiringMap =
+          new PassiveExpiringMap<String, Cursor>(EXPIRING_TIME);
+      resultsCache = Collections.synchronizedMap(resultsCacheExpiringMap);
+    }
+    return resultsCache;
+  }
+
+  /**
+   * 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 + "*";
+    String curl = null;
+    try {
+      JSONObject response = new JSONObject();
+      List<String> tables = ConnectionPool.getConnection(context).ddl().getDBList(like);
+      response.put("databases", tables);
+      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.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("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+    String curl = null;
+    try {
+      final String finalLike = like;
+      return ResultsPaginationController.getInstance(context)
+          .request("databases", searchId, false, fromBeginning, count,
+              new Callable<Cursor>() {
+                @Override
+                public Cursor call() throws Exception {
+                  return ConnectionPool.getConnection(context).ddl().getDBListCursor(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 + "*";
+    String curl = null;
+    try {
+      JSONObject response = new JSONObject();
+      List<String> tables = ConnectionPool.getConnection(context).ddl().getTableList(db, like);
+      response.put("tables", tables);
+      response.put("database", db);
+      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.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("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+    String curl = null;
+    try {
+      final String finalLike = like;
+      return ResultsPaginationController.getInstance(context)
+          .request(db + ":tables", searchId, false, fromBeginning, count,
+              new Callable<Cursor>() {
+                @Override
+                public Cursor call() throws Exception {
+                  Cursor cursor = ConnectionPool.getConnection(context).ddl().getTableListCursor(db, finalLike);
+                  cursor.selectColumns(requestedColumns);
+                  return cursor;
+                }
+              }).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}")
+  @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();
+      List<ColumnDescription> columnDescriptions = ConnectionPool.getConnection(context).ddl()
+          .getTableDescription(db, table, like, extendedTableDescription);
+      response.put("columns", columnDescriptions);
+      response.put("database", db);
+      response.put("table", table);
+      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") final String like,
+                                         @QueryParam("first") String fromBeginning,
+                                         @QueryParam("searchId") String searchId,
+                                         @QueryParam("count") Integer count,
+                                         @QueryParam("columns") final String requestedColumns) {
+    String curl = null;
+    try {
+      return ResultsPaginationController.getInstance(context)
+          .request(db + ":tables:" + table + ":columns", searchId, false, fromBeginning, count,
+              new Callable<Cursor>() {
+                @Override
+                public Cursor call() throws Exception {
+                  Cursor cursor = ConnectionPool.getConnection(context).ddl().getTableDescriptionCursor(db, table, like);
+                  cursor.selectColumns(requestedColumns);
+                  return cursor;
+                }
+              }).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);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileResource.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileResource.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileResource.java
new file mode 100644
index 0000000..633e859
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileService.java
new file mode 100644
index 0000000..8d886d5
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/files/FileService.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.hive.resources.files;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.utils.*;
+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.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;
+
+/**
+ * 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 {
+  @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 {
+      FilePaginator paginator = new FilePaginator(filePath, context);
+
+      if (page == null)
+        page = 0L;
+
+      FileResource file = new FileResource();
+      file.setFilePath(filePath);
+      file.setFileContent(paginator.readPage(page));
+      file.setHasNext(paginator.pageCount() > page + 1);
+      file.setPage(page);
+      file.setPageCount(paginator.pageCount());
+
+      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);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{filePath:.*}")
+  public Response deleteFile(@PathParam("filePath") String filePath) throws IOException, InterruptedException {
+    try {
+      LOG.debug("Deleting file " + filePath);
+      if (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 {
+      LOG.debug("Rewriting file " + filePath);
+      FSDataOutputStream output = 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 = getHdfsApi().create(request.file.getFilePath(), false);
+        if (request.file.getFileContent() != null) {
+          output.writeBytes(request.file.getFileContent());
+        }
+        output.close();
+      } catch (FileAlreadyExistsException ex) {
+        throw new ServiceFormattedException(ex.getMessage(), 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 = HdfsApi.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;
+  }
+}


[07/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
new file mode 100644
index 0000000..dc75280
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
@@ -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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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();
+    }
+  }.observes('content'),
+
+  getExplain: function () {
+    var self = this;
+    var url = this.container.lookup('adapter:application').buildURL();
+    url += '/' + constants.namingConventions.jobs + '/' + this.get('content.id') + '/results?first=true';
+
+    Ember.$.getJSON(url).then(function (data) {
+      var explainSet = self.get('cachedExplains').pushObject(Ember.Object.create({
+        id: self.get('content.id'),
+        explain: data
+      }));
+
+      self.set('content.explain', explainSet);
+
+      self.formatExplainResults(explainSet);
+    });
+  },
+
+  formatExplainResults: function (explainSet) {
+    var formatted = [],
+        orderedNodes = [],
+        currentNode,
+        currentNodeWhitespace,
+        previousNode,
+        formattedExplain = [],
+        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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
new file mode 100644
index 0000000..f633dd4
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.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 constants from 'hive/utils/constants';
+
+export default Ember.ObjectController.extend({
+  needs: [ constants.namingConventions.loadedFiles ],
+
+  files: Ember.computed.alias('controllers.' + constants.namingConventions.loadedFiles),
+
+  reloadJobLogs: function (job) {
+    var self = this,
+        defer = Ember.RSVP.defer(),
+        handleError = function (err) {
+          self.send('addAlert', constants.namingConventions.alerts.error, err.responseText);
+          defer.reject();
+        };
+
+    job.reload().then(function () {
+      self.get('files').reload(job.get('logFile')).then(function (file) {
+        var fileContent = file.get('fileContent');
+
+        if (fileContent) {
+          job.set('log', fileContent);
+        }
+
+        defer.resolve();
+      },function (err) {
+        handleError(err);
+      });
+    }, function (err) {
+      handleError(err);
+    });
+
+    return defer.promise;
+  },
+
+  listenForUpdates: function (job) {
+    Ember.run.later(this, function () {
+      var self = this;
+
+      this.reloadJobLogs(job).then(function () {
+        var stillRunning = self.isJobRunning(job);
+
+        //if the current model is the same with the one displayed, continue reloading job
+        if (stillRunning && job.get('id') === self.get('content.id')) {
+          self.listenForUpdates(job);
+        } else if (!stillRunning) {
+          job.set('isRunning', undefined);
+
+          if (job.get('id') === self.get('content.id')) {
+            self.transitionToRoute(constants.namingConventions.subroutes.jobResults);
+          }
+        }
+      });
+    }, 2000);
+  },
+
+  isJobRunning: function (job) {
+    var status = job.get('status');
+
+    return status !== constants.statuses.finished &&
+           status !== constants.statuses.canceled &&
+           status !== constants.statuses.closed &&
+           status !== constants.statuses.error;
+  },
+
+  getLogs: function () {
+    var self = this,
+        job = this.get('content');
+
+    if (this.isJobRunning(job)) {
+      job.set('isRunning', true);
+      this.reloadJobLogs(job).then(function () {
+        self.listenForUpdates(job);
+      });
+    }
+  }.observes('content')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
new file mode 100644
index 0000000..34e69bd
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.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.ObjectController.extend({
+  cachedResults: [],
+
+  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.send('getNextPage', true, job);
+          } 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 (this.get('content.status') !== constants.statuses.finished) {
+      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'),
+
+  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;
+        }
+      }
+
+      Ember.$.getJSON(url).then(function (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));
+      }
+    }
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js
new file mode 100644
index 0000000..fcfd113
--- /dev/null
+++ b/contrib/views/hive/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, constants.namingConventions.fileResources ],
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/job.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/job.js
new file mode 100644
index 0000000..5bb1cd5
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/job.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 constants from 'hive/utils/constants';
+
+export default Ember.ObjectController.extend({
+  needs: [ constants.namingConventions.history, constants.namingConventions.loadedFiles ],
+
+  files: Ember.computed.alias('controllers.' + constants.namingConventions.loadedFiles),
+
+  canStop: function () {
+    return this.get('status') === constants.statuses.running ||
+           this.get('status') === constants.statuses.initialized ||
+           this.get('status') === constants.statuses.pending;
+  }.property('status'),
+
+  actions: {
+    loadFile: function () {
+      var self = this;
+      if (!this.get('file')) {
+        this.get('files').loadFile(this.get('model.queryFile')).then(function (file) {
+          self.set('file', file);
+        });
+      }
+
+      this.set('expanded', !this.get('expanded'));
+    },
+
+    stop: function () {
+      this.send('interruptJob', this.get('model'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/loaded-files.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/loaded-files.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/loaded-files.js
new file mode 100644
index 0000000..3a11171
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/loaded-files.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend({
+  contains: function (obj) {
+    if (typeof obj === 'string') {
+      return this.findBy('id', obj);
+    }
+
+    return this._super(obj);
+  },
+
+  loadFile: function (path) {
+    var self = this;
+    var defer = Ember.RSVP.defer();
+    var file = this.contains(path);
+
+    if (file) {
+      defer.resolve(file);
+    } else {
+      this.store.find(constants.namingConventions.file, path).then(function (file) {
+        self.pushObject(file);
+        defer.resolve(file);
+      }, function (err) {
+        defer.reject(err);
+      });
+    }
+
+    return defer.promise;
+  },
+
+  reload: function (path) {
+    var defer = Ember.RSVP.defer();
+
+    this.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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-delete.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-delete.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-delete.js
new file mode 100644
index 0000000..0fbcd6b
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.js
new file mode 100644
index 0000000..6dc1349
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.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: {
+    save: function () {
+      this.send('closeModal');
+      this.defer.resolve(this.get('text'));
+    },
+
+    close: function () {
+      this.send('closeModal');
+      this.defer.reject();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
new file mode 100644
index 0000000..e97c0e6
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/open-queries.js
@@ -0,0 +1,320 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend({
+  needs: [ constants.namingConventions.databases,
+           constants.namingConventions.loadedFiles,
+           constants.namingConventions.jobResults,
+           constants.namingConventions.jobExplain,
+           constants.namingConventions.columns,
+           constants.namingConventions.index,
+           constants.namingConventions.settings
+         ],
+
+  databases: Ember.computed.alias('controllers.' + constants.namingConventions.databases),
+
+  files: Ember.computed.alias('controllers.' + constants.namingConventions.loadedFiles),
+
+  jobResults: Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+
+  jobExplain: Ember.computed.alias('controllers.' + constants.namingConventions.jobExplain),
+
+  index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+
+  settings: Ember.computed.alias('controllers.' + constants.namingConventions.settings),
+
+  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;
+
+          if (model.get('constructor.typeKey') === constants.namingConventions.job) {
+            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('files').loadFile(model.get('queryFile')).then(function (file) {
+          self.set('currentQuery', self.pushObject(file));
+
+          updateSubroute();
+        });
+
+        if (model.get('logFile') && !model.get('log')) {
+          this.get('files').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) {
+    var tab = this.getTabForModel(model),
+        self = this,
+        wasNew,
+        defer = Ember.RSVP.defer(),
+        jobModel = model,
+        originalId = model.get('id');
+
+    if (!query) {
+      query = this.getQueryForModel(model);
+    }
+
+    if (model.get('isNew')) {
+      wasNew = true;
+      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('databases.selectedDatabase.name'),
+        title: model.get('title'),
+        queryFile: model.get('queryFile'),
+        owner: model.get('owner')
+      });
+    }
+
+    model.save().then(function (updatedModel) {
+      tab.set('name', updatedModel.get('title'));
+      jobModel.set('queryId', updatedModel.get('id'));
+
+      var content = self.get('index').prependQuerySettings(query.get('fileContent'));
+      //update query tab path with saved model id if its a new record
+      if (wasNew) {
+        self.get('settings').updateSettingsId(originalId, updatedModel.get('id'));
+        tab.set('id', updatedModel.get('id'));
+
+        self.get('files').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();
+          }, function (err) {
+            defer.reject(err);
+          });
+        }, function (err) {
+          defer.reject(err);
+        });
+      } else {
+        query.set('fileContent', content);
+        query.save().then(function () {
+          self.toggleProperty('tabUpdated');
+          defer.resolve();
+        }, 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('files').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'));
+      }
+
+      self.removeObject(oldQuery);
+      self.pushObject(file);
+
+      defer.resolve();
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  keepOriginalQuery: function (jobId) {
+    var selected = this.get('highlightedText');
+    var hasQueryParams = this.get('index.queryParams.length');
+    var hasSettings = this.get('settings').hasSettings(jobId);
+
+    if ( selected && selected[0] !== "" ||
+         hasQueryParams ||
+         hasSettings ) {
+      return true;
+    }
+
+    return false;
+  },
+
+  actions: {
+    removeQueryTab: function (tab) {
+      var self = this,
+          defer,
+          remainingTabs = this.get('queryTabs').without(tab),
+          lastTab = remainingTabs.get('lastObject'),
+          closeTab = function () {
+            self.set('queryTabs', remainingTabs);
+
+            //remove cached results set
+            if (tab.type === constants.namingConventions.job) {
+              self.get('jobResults').clearCachedResultsSet(tab.id);
+              self.get('jobExplain').clearCachedExplainSet(tab.id);
+            }
+
+            if (lastTab.type === constants.namingConventions.job) {
+              self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, lastTab.id);
+            } else {
+              self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, lastTab.id);
+            }
+          };
+
+      this.store.find(tab.type, tab.id).then(function (model) {
+        var query = self.getQueryForModel(model);
+
+        if ((model.get('isNew') && !query.get('fileContent')) ||
+            (!model.get('isNew') && !query.get('isDirty'))) {
+          closeTab();
+        } 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).then(function () {
+              closeTab();
+            });
+          }, function () {
+            model.rollback();
+            closeTab();
+          });
+        }
+      });
+    },
+
+    getColumnsForAutocomplete: function (tableName, callback) {
+      this.get('databases').getAllColumns(tableName).then(function () {
+        callback();
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
new file mode 100644
index 0000000..85730a4
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/queries.js
@@ -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.
+ */
+
+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 ],
+
+  sortAscending: true,
+  sortProperties: [],
+
+  init: function () {
+    var oneYearAgo = new Date();
+    oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
+
+    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 () {
+    var queries = this.get('queries');
+    queries = queries ? queries.filterBy('isNew', false) : queries;
+
+    return this.filter(queries);
+  }.property('queries', 'filters.@each'),
+
+  actions: {
+    executeAction: function (action, savedQuery) {
+      switch (action) {
+        case "buttons.history":
+          this.get('controllers.' + constants.namingConventions.routes.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();
+          });
+
+          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 ]);
+      }
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.js
new file mode 100644
index 0000000..51101c5
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/settings.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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend({
+  needs: [
+    constants.namingConventions.index,
+    constants.namingConventions.openQueries
+  ],
+
+  index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+  openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+
+  showSettingsOverlay: false,
+
+  querySettings: function () {
+    var currentId = this.get('index.model.id');
+    return this.findBy('id', currentId);
+  }.property('model.[]', 'index.model.id'),
+
+  updateSettingsId: function (oldId, newId) {
+    this.filterBy('id', oldId).setEach('id', newId);
+  },
+
+  getSettingsString: function (id) {
+    var currentId = id ? id : this.get('index.model.id');
+
+    var querySettings = this.findBy('id', currentId);
+
+    if (!querySettings) {
+      return "";
+    }
+
+    var settings = querySettings.get('settings').map(function (setting) {
+      return 'set %@ = %@;'.fmt(setting.key, setting.value);
+    });
+
+    if (querySettings.get('runOnTez')) {
+      settings.push('set %@ = tez;'.fmt(constants.settings.executionEngine));
+    }
+
+    return settings.join("\n");
+  },
+
+  hasSettings: function (id) {
+    id = id ? id : this.get('index.model.id');
+    var settings = this.findBy('id', id);
+
+    return settings && settings.get('settings.length');
+  },
+
+  parseQuerySettings: function () {
+    var id = this.get('index.model.id');
+    var query = this.get('openQueries.currentQuery');
+    var content = query.get('fileContent');
+    var runOnTez = false;
+
+
+    var regex = new RegExp(/^set\s+[\w-.]+(\s+|\s?)=(\s+|\s?)[\w-.]+(\s+|\s?);/gim);
+    var settings = content.match(regex);
+
+    if (!settings) {
+      return;
+    }
+
+    query.set('fileContent', content.replace(regex, '').trim());
+    settings = settings.map(function (setting) {
+      var KV = setting.split('=');
+
+      return {
+        key: KV[0].replace('set', '').trim(),
+        value: KV[1].replace(';', '').trim()
+      };
+    });
+
+    // remove runOnTez from settings
+    settings = settings.findBy('key', constants.settings.executionEngine).without(false);
+
+    this.setSettingForQuery(id, settings, !!runOnTez);
+  }.observes('openQueries.currentQuery', 'openQueries.tabUpdated'),
+
+  setSettingForQuery: function (id, settings, runOnTez) {
+    var querySettings = this.findBy('id', id);
+
+    if (!querySettings) {
+      this.pushObject(Ember.Object.create({
+        id: id,
+        settings: settings,
+        runOnTez: runOnTez
+      }));
+    } else {
+      querySettings.setProperties({
+        'settings': settings,
+        'runOnTez': runOnTez
+      });
+    }
+  },
+
+  createSettingsForQuery: function () {
+    var currentId = this.get('index.model.id');
+
+    if (!this.findBy('id', currentId)) {
+      this.pushObject(Ember.Object.create({
+        id: currentId,
+        settings: [],
+        runOnTez: false
+      }));
+    }
+  },
+
+  actions: {
+    toggleOverlay: function () {
+      // create a setting object if its not already there
+      this.createSettingsForQuery();
+      this.toggleProperty('showSettingsOverlay');
+    },
+
+    add: function () {
+      var currentId = this.get('index.model.id'),
+       querySettings = this.findBy('id', currentId);
+
+      querySettings.settings.pushObject(Ember.Object.create({
+        key: '',
+        value: ''
+      }));
+    },
+
+    remove: function (setting) {
+      var currentId = this.get('index.model.id');
+      this.findBy('id', currentId).settings.removeObject(setting);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/tables.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/tables.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/tables.js
new file mode 100644
index 0000000..1d773e7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/tables.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 Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ObjectController.extend({
+  pageCount: 10,
+
+  init: function () {
+    this._super();
+
+    var databaseAdapter = this.container.lookup('adapter:database');
+    var baseUrl = databaseAdapter.buildURL() + '/' +
+                  databaseAdapter.pathForType(constants.namingConventions.database) + '/';
+
+    this.set('baseUrl', baseUrl);
+  },
+
+  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;
+  },
+
+  getTables: function (databaseName) {
+    var defer = Ember.RSVP.defer(),
+        url = this.get('baseUrl') +
+              databaseName +
+              '/table';
+
+    Ember.$.getJSON(url).then(function (data) {
+      var tables = data.tables.map(function (table) {
+        return Ember.Object.create({
+          name: table
+        });
+      });
+
+      defer.resolve(tables);
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.js
new file mode 100644
index 0000000..657743c
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udf.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 constants from 'hive/utils/constants';
+
+export default Ember.ObjectController.extend({
+  needs: [ constants.namingConventions.udfs, constants.namingConventions.fileResources ],
+
+  columns: Ember.computed.alias('controllers.' + constants.namingConventions.udfs + '.columns'),
+  links: Ember.computed.alias('controllers.' + constants.namingConventions.udfs + '.links'),
+  fileResources: Ember.computed.alias('controllers.' + constants.namingConventions.fileResources),
+
+  init: function () {
+    this._super();
+
+    if (this.get('model.isNew')) {
+      this.set('isEditing', true);
+    }
+
+    // we need this because model.rollback doesnt roll back secondary relations
+    this.set('fileBackup', this.get('model.fileResource'));
+  },
+
+  actions: {
+    executeAction: function (action) {
+      switch (action) {
+        case 'buttons.edit':
+          this.set('isEditing', true);
+          break;
+        case 'buttons.delete':
+          var defer = Ember.RSVP.defer(),
+              self = this;
+
+          this.send('openModal',
+                    'modal-delete',
+                     {
+                        heading: Ember.I18n.translations.modals.delete.heading,
+                        text: Ember.I18n.translations.modals.delete.message,
+                        defer: defer
+                     });
+
+          defer.promise.then(function () {
+            self.get('model').destroyRecord();
+          });
+          break;
+      }
+    },
+
+    save: function () {
+      var self = this,
+          saveUdf = function () {
+            self.get('model').save().then(function (updatedModel) {
+              self.set('isEditing', false);
+              self.set('isEditingResource', false);
+              self.set('fileBackup', updatedModel.get('fileResource'));
+            });
+          };
+
+      //replace with a validation system if needed.
+      if (!this.get('model.name') || !this.get('model.classname')) {
+        return;
+      }
+
+      this.get('model.fileResource').then(function (file) {
+        if (file) {
+          if (!file.get('name') || !file.get('path')) {
+            return;
+          }
+
+          file.save().then(function () {
+            saveUdf();
+          });
+        } else {
+          saveUdf();
+        }
+      });
+    },
+
+    cancel: function () {
+      var self = this;
+
+      this.set('isEditing', false);
+      this.set('isEditingResource', false);
+
+      this.model.get('fileResource').then(function (file) {
+        if (file) {
+          file.rollback();
+        }
+
+        self.model.rollback();
+        self.model.set('fileResource', self.get('fileBackup'));
+      });
+    },
+
+    addFileResource: function () {
+      var file = this.store.createRecord(constants.namingConventions.fileResource);
+      this.set('isEditingResource', true);
+      this.model.set('fileResource', file);
+    },
+
+    editFileResource: function (file) {
+      this.set('isEditingResource', true);
+      this.model.set('fileResource', file);
+    },
+
+    removeFileResource: function (file) {
+      var defer = Ember.RSVP.defer();
+
+      this.send('openModal',
+                'modal-delete',
+                 {
+                    heading: Ember.I18n.translations.modals.delete.heading,
+                    text: Ember.I18n.translations.modals.delete.message,
+                    defer: defer
+                 });
+
+      defer.promise.then(function () {
+        file.destroyRecord();
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udfs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udfs.js
new file mode 100644
index 0000000..52faba1
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/udfs.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 FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+  itemController: constants.namingConventions.udf,
+
+  sortAscending: true,
+  sortProperties: [],
+
+  init: function () {
+    this._super();
+
+    this.set('columns', Ember.ArrayProxy.create({ content: Ember.A([
+      Ember.Object.create({
+        caption: 'placeholders.udfs.name',
+        property: 'name'
+      }),
+      Ember.Object.create({
+        caption: 'placeholders.udfs.className',
+        property: 'classname'
+      })
+    ])}));
+  },
+
+  //row buttons
+  links: [
+      'buttons.edit',
+      'buttons.delete'
+  ],
+
+  model: function () {
+    return this.filter(this.get('udfs'));
+  }.property('udfs', 'filters.@each'),
+
+  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 ]);
+      }
+    },
+
+    add: function () {
+      this.store.createRecord(constants.namingConventions.udf);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/code-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/code-helper.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/code-helper.js
new file mode 100644
index 0000000..327636f
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/date-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/date-binding.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/date-binding.js
new file mode 100644
index 0000000..4baeca8
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/log-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/log-helper.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/log-helper.js
new file mode 100644
index 0000000..c603c60
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/path-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/path-binding.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/path-binding.js
new file mode 100644
index 0000000..e53772e
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/tb-helper.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
new file mode 100644
index 0000000..fcce185
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html b/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
new file mode 100644
index 0000000..4f609bd
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/index.html
@@ -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.
+-->
+<!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">
+  </head>
+  <body>
+    {{content-for 'body'}}
+
+    <script src="assets/vendor.js"></script>
+    <script src="assets/hive.js"></script>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
new file mode 100644
index 0000000..0040307
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
@@ -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.
+ */
+
+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 = {
+  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.'
+      }
+    }
+  },
+  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:'
+    }
+  },
+  titles: {
+    database: 'Database Explorer',
+    explorer: 'Databases',
+    results: 'Search Results',
+    settings: 'Database Settings',
+    query: {
+      editor: 'Query Editor',
+      process: 'Query Process Results',
+      parameters: 'Parameters'
+    },
+    download: 'Save results...'
+  },
+  placeholders: {
+    search: {
+      tables: 'Search tables...',
+      columns: 'Search columns in result tables...'
+    },
+    select: {
+      database: 'Select Database...',
+      udfs: 'Insert udfs',
+      file: 'Select File Resource...',
+      noFileResource: '(no file)'
+    },
+    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',
+    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 Query',
+    newUdf: 'New UDF',
+    history: 'History',
+    ok: 'OK',
+    stopJob: 'Stop execution',
+    close: 'Close',
+    clearFilters: 'Clear filters',
+    expand: 'Expand message',
+    collapse: 'Collapse message',
+    previousPage: 'previous',
+    nextPage: 'next',
+    loadMore: 'Load more...',
+    saveHdfs: 'Save to HDFS',
+    saveCsv: 'Download as CSV',
+    runOnTez: 'Run on Tez'
+  },
+  labels: {
+    noTablesMatches: 'No tables matches for'
+  },
+  popover: {
+    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'
+  }
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/filterable.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/filterable.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/filterable.js
new file mode 100644
index 0000000..55d4593
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/filterable.js
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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 () {
+      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 () {
+    if (!this.get('filters') || this.get('filters.length')) {
+      this.set('filters', Ember.A());
+    }
+  },
+
+  actions: {
+    filter: function (property, filterValue) {
+      this.updateFilters(property, filterValue);
+    },
+
+    clearFilters: function () {
+      this.clearFilters();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/sortable.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/sortable.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/mixins/sortable.js
new file mode 100644
index 0000000..f766032
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/database.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/database.js
new file mode 100644
index 0000000..11ee144
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file-resource.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file-resource.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file-resource.js
new file mode 100644
index 0000000..47f4911
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/file.js
new file mode 100644
index 0000000..f8f1b9b
--- /dev/null
+++ b/contrib/views/hive/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,
+  pageCount: DS.attr()
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
new file mode 100644
index 0000000..95e5d57
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/job.js
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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'),
+  dateSubmitted: DS.attr('date'),
+  forcedContent: DS.attr('string'),
+  logFile: DS.attr('string')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/saved-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/saved-query.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/saved-query.js
new file mode 100644
index 0000000..44536af
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/models/udf.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/models/udf.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/models/udf.js
new file mode 100644
index 0000000..c64221e
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/router.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/router.js
new file mode 100644
index 0000000..244bc58
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/router.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.
+ */
+
+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.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');
+});
+
+export default Router;

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


[10/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ConnectionController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ConnectionController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ConnectionController.java
new file mode 100644
index 0000000..8f143e7
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ConnectionController.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.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.client.Connection;
+import org.apache.ambari.view.hive.client.ConnectionPool;
+import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConnectionController {
+  private ViewContext context;
+  private Connection connection;
+  private OperationHandleControllerFactory operationHandleControllerFactory;
+
+  private ConnectionController(ViewContext context) {
+    this.context = context;
+    connection = ConnectionPool.getConnection(context);
+    operationHandleControllerFactory = OperationHandleControllerFactory.getInstance(context);
+  }
+
+  private static Map<String, ConnectionController> viewSingletonObjects = new HashMap<String, ConnectionController>();
+  public static ConnectionController getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new ConnectionController(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public void selectDatabase(String database) {
+    executeQuery("use " + database + ";");
+  }
+
+  public OperationHandleController executeQuery(String cmd) {
+    TOperationHandle operationHandle = null;
+    try {
+      operationHandle = connection.executeAsync(cmd);
+    } catch (HiveClientException e) {
+      throw new ServiceFormattedException(e.toString(), e);
+    }
+    return operationHandleControllerFactory.createControllerForHandle(operationHandle);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/FileResourceShort.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/FileResourceShort.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/FileResourceShort.java
new file mode 100644
index 0000000..776bf64
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/FileResourceShort.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.view.hive.resources.jobs;
+
+import org.apache.commons.beanutils.BeanUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+public class FileResourceShort {
+  public FileResourceShort() {}
+  public FileResourceShort(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  private Integer id;
+  private String path;
+
+  public FileResourceShort(Integer id, String path) {
+    this.id = id;
+    this.path = path;
+  }
+
+  public Integer getId() {
+    return id;
+  }
+
+  public void setId(Integer id) {
+    this.id = id;
+  }
+
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/Job.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/Job.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/Job.java
new file mode 100644
index 0000000..e6f7a63
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/Job.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.jobs;
+
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.persistence.utils.PersonalResource;
+
+import java.io.Serializable;
+
+/**
+ * Interface for Job bean to create Proxy for it
+ */
+public interface Job extends Serializable,Indexed,PersonalResource {
+  public static final String JOB_STATE_UNKNOWN = "Unknown";
+  public static final String JOB_STATE_INITIALIZED = "Initialized";
+  public static final String JOB_STATE_RUNNING = "Running";
+  public static final String JOB_STATE_FINISHED = "Finished";
+  public static final String JOB_STATE_CANCELED = "Canceled";
+  public static final String JOB_STATE_CLOSED = "Closed";
+  public static final String JOB_STATE_ERROR = "Error";
+  public static final String JOB_STATE_PENDING = "Pending";
+
+  Integer getId();
+
+  void setId(Integer 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);
+
+  Integer getQueryId();
+
+  void setQueryId(Integer 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);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobController.java
new file mode 100644
index 0000000..3d5189e
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobController.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.hive.resources.jobs;
+
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+
+public interface JobController {
+  void submit();
+
+  void cancel() throws ItemNotFound;
+
+  Job getJob();
+
+  /**
+   * Use carefully. Returns unproxied bean object
+   * @return unproxied bean object
+   */
+  Job getJobPOJO();
+
+  Cursor getResults() throws ItemNotFound;
+
+  void afterCreation();
+
+  void onRead();
+
+  boolean isModified();
+
+  void clearModified();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerFactory.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerFactory.java
new file mode 100644
index 0000000..f6ec5b1
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerFactory.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.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class JobControllerFactory {
+  private ViewContext context;
+
+  private JobControllerFactory(ViewContext context) {
+    this.context = context;
+  }
+
+  private static Map<String, JobControllerFactory> viewSingletonObjects = new HashMap<String, JobControllerFactory>();
+  public static JobControllerFactory getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new JobControllerFactory(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public JobController createControllerForJob(Job job) {
+    return new JobControllerImpl(context, job);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerImpl.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerImpl.java
new file mode 100644
index 0000000..a9f315c
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobControllerImpl.java
@@ -0,0 +1,326 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.client.*;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.resources.savedQueries.SavedQuery;
+import org.apache.ambari.view.hive.resources.savedQueries.SavedQueryResourceManager;
+import org.apache.ambari.view.hive.utils.*;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+import org.apache.ambari.view.hive.utils.HdfsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class JobControllerImpl implements JobController, ModifyNotificationDelegate {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(JobControllerImpl.class);
+
+  private ViewContext context;
+  private Job jobUnproxied;
+  private Job job;
+  private boolean modified;
+
+  private OperationHandleControllerFactory operationHandleControllerFactory;
+  private ConnectionController hiveSession;
+  private SavedQueryResourceManager savedQueryResourceManager;
+
+  /**
+   * JobController constructor
+   * Warning: Create JobControllers ONLY using JobControllerFactory!
+   */
+  public JobControllerImpl(ViewContext context, Job job) {
+    this.context = context;
+    setJobPOJO(job);
+    operationHandleControllerFactory = OperationHandleControllerFactory.getInstance(context);
+    hiveSession = ConnectionController.getInstance(context);
+    savedQueryResourceManager = SavedQueryResourceManager.getInstance(context);
+  }
+
+  public String getQueryForJob() {
+    FilePaginator paginator = new FilePaginator(job.getQueryFile(), context);
+    String query;
+    try {
+      query = paginator.readPage(0);  //warning - reading only 0 page restricts size of query to 1MB
+    } catch (IOException e) {
+      throw new ServiceFormattedException("Error when reading file: " + e.toString(), e);
+    } catch (InterruptedException e) {
+      throw new ServiceFormattedException("Error when reading file: " + e.toString(), 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() {
+    setupHiveBeforeQueryExecute();
+
+    String query = getQueryForJob();
+    OperationHandleController handleController = hiveSession.executeQuery(query);
+
+    handleController.persistHandleForJob(job);
+  }
+
+  private void setupHiveBeforeQueryExecute() {
+    String database = getJobDatabase();
+    hiveSession.selectDatabase(database);
+  }
+
+  @Override
+  public void cancel() throws ItemNotFound {
+    OperationHandleController handle = operationHandleControllerFactory.getHandleForJob(job);
+    handle.cancel();
+  }
+
+  @Override
+  public void onRead() {
+    updateOperationStatus();
+    updateOperationLogs();
+
+    updateJobDuration();
+  }
+
+  public void updateOperationStatus() {
+    try {
+
+      OperationHandleController handle = operationHandleControllerFactory.getHandleForJob(job);
+      String status = handle.getOperationStatus();
+      job.setStatus(status);
+      LOG.debug("Status of job#" + job.getId() + " is " + job.getStatus());
+
+    } catch (NoOperationStatusSetException e) {
+      LOG.info("Operation state is not set for job#" + job.getId());
+
+    } catch (HiveErrorStatusException e) {
+      LOG.debug("Error updating status for job#" + job.getId() + ": " + e.getMessage());
+      job.setStatus(Job.JOB_STATE_UNKNOWN);
+
+    } catch (HiveClientException e) {
+      throw new ServiceFormattedException("Could not fetch job status " + job.getId(), e);
+
+    } catch (ItemNotFound itemNotFound) {
+      LOG.debug("No TOperationHandle for job#" + job.getId() + ", can't update status");
+    }
+  }
+
+  public void updateOperationLogs() {
+    try {
+      OperationHandleController handle = operationHandleControllerFactory.getHandleForJob(job);
+      String logs = handle.getLogs();
+
+//      LogParser info = LogParser.parseLog(logs);
+
+      String logFilePath = job.getLogFile();
+      HdfsUtil.putStringToFile(context, logFilePath, logs);
+
+    } catch (HiveClientRuntimeException ex) {
+      LOG.error("Error while fetching logs: " + ex.getMessage());
+    } catch (ItemNotFound itemNotFound) {
+      LOG.debug("No TOperationHandle for job#" + job.getId() + ", can't read logs");
+    }
+  }
+
+  public boolean isJobEnded() {
+    String status = job.getStatus();
+    return status.equals(Job.JOB_STATE_FINISHED) || status.equals(Job.JOB_STATE_CANCELED) ||
+        status.equals(Job.JOB_STATE_CLOSED) || status.equals(Job.JOB_STATE_ERROR) ||
+        status.equals(Job.JOB_STATE_UNKNOWN); // Unknown is not finished, but polling makes no sense
+  }
+
+  @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 Cursor getResults() throws ItemNotFound {
+    OperationHandleController handle = operationHandleControllerFactory.getHandleForJob(job);
+    return handle.getResults();
+  }
+
+  @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";
+    HdfsUtil.putStringToFile(context, logFile, "");
+
+    job.setLogFile(logFile);
+    LOG.debug("Log file for job#" + job.getId() + ": " + logFile);
+  }
+
+  private void setupStatusDir() {
+    String newDirPrefix = makeStatusDirectoryPrefix();
+    String newDir = HdfsUtil.findUnallocatedFileName(context, newDirPrefix, "");
+
+    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-%d", 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(context, jobQueryFilePath, job.getForcedContent());
+        job.setForcedContent("");  // prevent forcedContent to be written to DB
+
+      }
+      else if (job.getQueryId() != null) {
+
+        String savedQueryFile = getRelatedSavedQueryFile();
+        HdfsApi.getInstance(context).copy(savedQueryFile, jobQueryFilePath);
+        job.setQueryFile(jobQueryFilePath);
+
+      } else {
+
+        throw new BadRequestFormattedException("queryId or forcedContent should be passed!", null);
+
+      }
+
+    } catch (IOException e) {
+      throw new ServiceFormattedException("Error in creation: " + e.toString(), e);
+    } catch (InterruptedException e) {
+      throw new ServiceFormattedException("Error in creation: " + e.toString(), e);
+    }
+    job.setQueryFile(jobQueryFilePath);
+
+    LOG.debug("Query file for job#" + job.getId() + ": " + jobQueryFilePath);
+  }
+
+  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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobImpl.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobImpl.java
new file mode 100644
index 0000000..7d65957
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobImpl.java
@@ -0,0 +1,203 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.jobs;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+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 status = JOB_STATE_UNKNOWN;
+  private String forcedContent = null;
+  private String dataBase = null;
+  private Integer queryId = null;
+
+  private Integer id = null;
+  private String owner = null;
+
+  private String logFile;
+  private String confFile;
+
+  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 Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(Integer 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
+  public String getForcedContent() {
+    return forcedContent;
+  }
+
+  @Override
+  public void setForcedContent(String forcedContent) {
+    this.forcedContent = forcedContent;
+  }
+
+  @Override
+  public Integer getQueryId() {
+    return queryId;
+  }
+
+  @Override
+  public void setQueryId(Integer 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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceManager.java
new file mode 100644
index 0000000..139b29a
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceManager.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.client.*;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive.utils.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * Object that provides CRUD operations for query objects
+ */
+public class JobResourceManager extends PersonalCRUDResourceManager<Job> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(JobResourceManager.class);
+
+  private JobControllerFactory jobControllerFactory;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public JobResourceManager(ViewContext context) {
+    super(JobImpl.class, context);
+    jobControllerFactory = JobControllerFactory.getInstance(context);
+  }
+
+  @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;
+  }
+
+  private void saveIfModified(JobController jobController) {
+    if (jobController.isModified()) {
+      save(jobController.getJobPOJO());
+      jobController.clearModified();
+    }
+  }
+
+
+  @Override
+  public Job read(Integer id) throws ItemNotFound {
+    Job job = super.read(id);
+    JobController jobController =  jobControllerFactory.createControllerForJob(job);
+    jobController.onRead();
+    saveIfModified(jobController);
+    return job;
+  }
+
+  @Override
+  public List<Job> readAll(FilteringStrategy filteringStrategy) {
+    return super.readAll(filteringStrategy);
+  }
+
+  @Override
+  public void delete(Integer resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+
+  public JobController readController(Integer id) throws ItemNotFound {
+    Job job = read(id);
+    return jobControllerFactory.createControllerForJob(job);
+  }
+
+  public Cursor getJobResultsCursor(Job job) {
+    try {
+      JobController jobController = jobControllerFactory.createControllerForJob(job);
+      return jobController.getResults();
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException("Job results are expired", null);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceProvider.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceProvider.java
new file mode 100644
index 0000000..780921d
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobResourceProvider.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.hive.resources.jobs;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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(context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public Job getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<Job> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    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 = JobControllerFactory.getInstance(context).createControllerForJob(item);
+    jobController.submit();
+  }
+
+  @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, Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
new file mode 100644
index 0000000..1c4f2a9
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
@@ -0,0 +1,355 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.jobs;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.backgroundjobs.BackgroundJobController;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.utils.*;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+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.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+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;
+
+  protected JobResourceManager resourceManager;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(JobService.class);
+
+  protected synchronized JobResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new JobResourceManager(context);
+    }
+    return resourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{jobId}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("jobId") String jobId) {
+    try {
+      JobController jobController = getResourceManager().readController(Integer.valueOf(jobId));
+
+      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 {
+    Map createdJobMap = PropertyUtils.describe(jobController.getJob());
+    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("columns") final String requestedColumns) {
+    try {
+      JobController jobController = getResourceManager().readController(Integer.valueOf(jobId));
+      final Cursor resultSet = jobController.getResults();
+      resultSet.selectColumns(requestedColumns);
+
+      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 {
+            while (resultSet.hasNext()) {
+              csvPrinter.printRecord(resultSet.next().getRow());
+              writer.flush();
+            }
+          } finally {
+            writer.close();
+          }
+        }
+      };
+
+      return Response.ok(stream).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 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(Integer.valueOf(jobId));
+
+      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");
+        BackgroundJobController.getInstance(context).startJob(String.valueOf(backgroundJobId), new Runnable() {
+          @Override
+          public void run() {
+
+            try {
+              Cursor resultSet = jobController.getResults();
+              resultSet.selectColumns(requestedColumns);
+
+              FSDataOutputStream stream = HdfsApi.getInstance(context).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("Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            } catch (InterruptedException e) {
+              throw new ServiceFormattedException("Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            } catch (ItemNotFound itemNotFound) {
+              throw new NotFoundFormattedException("Job results are expired", itemNotFound);
+            }
+
+          }
+        });
+      }
+
+      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);
+    }
+  }
+
+  /**
+   * Get next results page
+   */
+  @GET
+  @Path("{jobId}/results")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getResults(@PathParam("jobId") String jobId,
+                             @QueryParam("first") String fromBeginning,
+                             @QueryParam("count") Integer count,
+                             @QueryParam("searchId") String searchId,
+                             @QueryParam("columns") final String requestedColumns) {
+    try {
+      final JobController jobController = getResourceManager().readController(Integer.valueOf(jobId));
+
+      return ResultsPaginationController.getInstance(context)
+           .request(jobId, searchId, true, fromBeginning, count,
+               new Callable<Cursor>() {
+                 @Override
+                 public Cursor call() throws Exception {
+                   Cursor cursor = jobController.getResults();
+                   cursor.selectColumns(requestedColumns);
+                   return cursor;
+                 }
+               }).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } 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);
+    }
+  }
+
+  /**
+   * 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(Integer.valueOf(id));
+      } catch (ItemNotFound itemNotFound) {
+        throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+      }
+      jobController.cancel();
+      if (remove != null && remove.compareTo("true") == 0) {
+        getResourceManager().delete(Integer.valueOf(id));
+      }
+//      getResourceManager().delete(Integer.valueOf(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 Jobs
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all job");
+      List allJobs = getResourceManager().readAll(
+          new OnlyOwnersFilteringStrategy(this.context.getUsername()));  //TODO: move strategy to PersonalCRUDRM
+
+      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();
+
+      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 (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class JobRequest {
+    public JobImpl job;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/LogParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/LogParser.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/LogParser.java
new file mode 100644
index 0000000..090781c
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/LogParser.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.hive.resources.jobs;
+
+import java.util.LinkedHashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LogParser {
+  public static final Pattern HADOOP_MR_JOBS_RE = Pattern.compile("(http[^\\s]*/proxy/([a-z0-9_]+?)/)");
+  public static final Pattern HADOOP_TEZ_JOBS_RE = Pattern.compile("\\(Executing on YARN cluster with App id ([a-z0-9_]+?)\\)");
+  private LinkedHashSet<JobId> jobsList;
+
+  public static LogParser parseLog(String logs) {
+    LogParser parser = new LogParser();
+
+    LinkedHashSet<JobId> mrJobIds = getMRJobIds(logs);
+    LinkedHashSet<JobId> tezJobIds = getTezJobIds(logs);
+
+    LinkedHashSet<JobId> jobIds = new LinkedHashSet<JobId>();
+    jobIds.addAll(mrJobIds);
+    jobIds.addAll(tezJobIds);
+
+    parser.setJobsList(jobIds);
+    return parser;
+  }
+
+  private static LinkedHashSet<JobId> getMRJobIds(String logs) {
+    Matcher m = HADOOP_MR_JOBS_RE.matcher(logs);
+    LinkedHashSet<JobId> list = new LinkedHashSet<JobId>();
+    while (m.find()) {
+      JobId applicationInfo = new JobId();
+      applicationInfo.setTrackingUrl(m.group(1));
+      applicationInfo.setIdentifier(m.group(2));
+      list.add(applicationInfo);
+    }
+    return list;
+  }
+
+  private static LinkedHashSet<JobId> getTezJobIds(String logs) {
+    Matcher m = HADOOP_TEZ_JOBS_RE.matcher(logs);
+    LinkedHashSet<JobId> list = new LinkedHashSet<JobId>();
+    while (m.find()) {
+      JobId applicationInfo = new JobId();
+      applicationInfo.setTrackingUrl(null);
+      applicationInfo.setIdentifier(m.group(1));
+      list.add(applicationInfo);
+    }
+    return list;
+  }
+
+  public void setJobsList(LinkedHashSet<JobId> jobsList) {
+    this.jobsList = jobsList;
+  }
+
+  public LinkedHashSet<JobId> getJobsList() {
+    return jobsList;
+  }
+
+  public static class JobId {
+    private String trackingUrl;
+    private String identifier;
+
+    public String getTrackingUrl() {
+      return trackingUrl;
+    }
+
+    public void setTrackingUrl(String trackingUrl) {
+      this.trackingUrl = trackingUrl;
+    }
+
+    public String getIdentifier() {
+      return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+      this.identifier = identifier;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (!(o instanceof JobId)) return false;
+
+      JobId jobId = (JobId) o;
+
+      if (!identifier.equals(jobId.identifier)) return false;
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      return identifier.hashCode();
+    }
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ModifyNotificationInvocationHandler.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ModifyNotificationInvocationHandler.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ModifyNotificationInvocationHandler.java
new file mode 100644
index 0000000..0552a8c
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/NoOperationStatusSetException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/NoOperationStatusSetException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/NoOperationStatusSetException.java
new file mode 100644
index 0000000..1c1ce91
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/NoOperationStatusSetException.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.hive.resources.jobs;
+
+
+public class NoOperationStatusSetException extends Throwable {
+  public NoOperationStatusSetException(String s) {
+    super(s);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.java
new file mode 100644
index 0000000..551ebdd
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.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.hive.resources.jobs;
+
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.client.ConnectionPool;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.hive.service.cli.thrift.TGetOperationStatusResp;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OperationHandleController {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(OperationHandleController.class);
+
+  private ViewContext context;
+  private TOperationHandle operationHandle;
+  private OperationHandleResourceManager operationHandlesStorage;
+
+  public OperationHandleController(ViewContext context, TOperationHandle storedOperationHandle, OperationHandleResourceManager operationHandlesStorage) {
+    this.context = context;
+    this.operationHandle = storedOperationHandle;
+    this.operationHandlesStorage = operationHandlesStorage;
+  }
+
+
+
+  public TOperationHandle getStoredOperationHandle() {
+    return operationHandle;
+  }
+
+  public void setStoredOperationHandle(TOperationHandle storedOperationHandle) {
+    this.operationHandle = storedOperationHandle;
+  }
+
+  public String getOperationStatus() throws NoOperationStatusSetException, HiveClientException {
+    TGetOperationStatusResp statusResp = ConnectionPool.getConnection(context).getOperationStatus(operationHandle);
+    if (!statusResp.isSetOperationState()) {
+      throw new NoOperationStatusSetException("Operation state is not set");
+    }
+
+    String status;
+    switch (statusResp.getOperationState()) {
+      case INITIALIZED_STATE:
+        status = Job.JOB_STATE_INITIALIZED;
+        break;
+      case RUNNING_STATE:
+        status = Job.JOB_STATE_RUNNING;
+        break;
+      case FINISHED_STATE:
+        status = Job.JOB_STATE_FINISHED;
+        break;
+      case CANCELED_STATE:
+        status = Job.JOB_STATE_CANCELED;
+        break;
+      case CLOSED_STATE:
+        status = Job.JOB_STATE_CLOSED;
+        break;
+      case ERROR_STATE:
+        status = Job.JOB_STATE_ERROR;
+        break;
+      case UKNOWN_STATE:
+        status = Job.JOB_STATE_UNKNOWN;
+        break;
+      case PENDING_STATE:
+        status = Job.JOB_STATE_PENDING;
+        break;
+      default:
+        throw new NoOperationStatusSetException("Unknown status " + statusResp.getOperationState());
+    }
+    return status;
+  }
+
+  public void cancel() {
+    try {
+      ConnectionPool.getConnection(context).cancelOperation(operationHandle);
+    } catch (HiveClientException e) {
+      throw new ServiceFormattedException("Cancel failed: " + e.toString(), e);
+    }
+  }
+
+  public void persistHandleForJob(Job job) {
+    operationHandlesStorage.putHandleForJob(operationHandle, job);
+  }
+
+  public String getLogs() {
+    return ConnectionPool.getConnection(context).getLogs(operationHandle);
+  }
+
+  public Cursor getResults() {
+    return ConnectionPool.getConnection(context).getResults(operationHandle);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.java
new file mode 100644
index 0000000..5d4a8af
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.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.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class OperationHandleControllerFactory {
+  private ViewContext context;
+  private OperationHandleResourceManager operationHandlesStorage;
+
+  private OperationHandleControllerFactory(ViewContext context) {
+    this.context = context;
+    operationHandlesStorage = new OperationHandleResourceManager(context);
+  }
+
+  private static Map<String, OperationHandleControllerFactory> viewSingletonObjects = new HashMap<String, OperationHandleControllerFactory>();
+  public static OperationHandleControllerFactory getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new OperationHandleControllerFactory(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public OperationHandleController createControllerForHandle(TOperationHandle storedOperationHandle) {
+    return new OperationHandleController(context, storedOperationHandle, operationHandlesStorage);
+  }
+
+  public OperationHandleController getHandleForJob(Job job) throws ItemNotFound {
+    TOperationHandle handle = operationHandlesStorage.getHandleForJob(job);
+    return createControllerForHandle(handle);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleResourceManager.java
new file mode 100644
index 0000000..cffed38
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleResourceManager.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.hive.resources.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.resources.SharedCRUDResourceManager;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.util.List;
+
+public class OperationHandleResourceManager extends SharedCRUDResourceManager<StoredOperationHandle> {
+  /**
+   * Constructor
+   *
+   * @param context       View Context instance
+   */
+  public OperationHandleResourceManager(ViewContext context) {
+    super(StoredOperationHandle.class, context);
+  }
+
+  public List<StoredOperationHandle> readJobRelatedHandles(final Job job) {
+    try {
+      return getStorage().loadWhere(StoredOperationHandle.class, "jobId = " + job.getId());
+    } catch (NotImplementedException e) {
+      // fallback to filtering strategy
+      return getStorage().loadAll(StoredOperationHandle.class, new FilteringStrategy() {
+        @Override
+        public boolean isConform(Indexed item) {
+          StoredOperationHandle handle = (StoredOperationHandle) item;
+          return (handle.getJobId() != null && handle.getJobId().equals(job.getId()));
+        }
+      });
+    }
+  }
+
+  public void putHandleForJob(TOperationHandle h, Job job) {
+    StoredOperationHandle handle = StoredOperationHandle.buildFromTOperationHandle(h);
+    handle.setJobId(job.getId());
+
+    List<StoredOperationHandle> jobRelatedHandles = readJobRelatedHandles(job);
+    if (jobRelatedHandles.size() > 0) {
+      handle.setId(jobRelatedHandles.get(0).getId());  // update existing
+      try {
+        update(handle, jobRelatedHandles.get(0).getId());
+      } catch (ItemNotFound itemNotFound) {
+        throw new ServiceFormattedException("Error when updating operation handle: " + itemNotFound.toString(), itemNotFound);
+      }
+    } else {
+      create(handle);
+    }
+  }
+
+  public boolean containsHandleForJob(Job job) {
+    List<StoredOperationHandle> jobRelatedHandles = readJobRelatedHandles(job);
+    return jobRelatedHandles.size() > 0;
+  }
+
+  public TOperationHandle getHandleForJob(Job job) throws ItemNotFound {
+    List<StoredOperationHandle> jobRelatedHandles = readJobRelatedHandles(job);
+    if (jobRelatedHandles.size() == 0)
+      throw new ItemNotFound();
+    return jobRelatedHandles.get(0).toTOperationHandle();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
new file mode 100644
index 0000000..c152b03
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.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.hive.resources.jobs;
+
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.client.ColumnDescription;
+import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.commons.collections4.map.PassiveExpiringMap;
+
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+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> resultsCache;
+
+  public static class CustomTimeToLiveExpirationPolicy extends PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<String, Cursor> {
+    public CustomTimeToLiveExpirationPolicy(long timeToLiveMillis) {
+      super(timeToLiveMillis);
+    }
+
+    @Override
+    public long expirationTime(String key, Cursor value) {
+      if (key.startsWith("$"))
+        return -1;  //never expire
+      return super.expirationTime(key, value);
+    }
+  }
+
+  private Map<String, Cursor> getResultsCache() {
+    if (resultsCache == null) {
+      PassiveExpiringMap<String, Cursor> resultsCacheExpiringMap =
+          new PassiveExpiringMap<String, Cursor>(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);
+    return true;
+  }
+
+  private Cursor getResultsSet(String key, Callable<Cursor> makeResultsSet) {
+    if (!getResultsCache().containsKey(key)) {
+      Cursor resultSet = null;
+      try {
+        resultSet = makeResultsSet.call();
+      } 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, Callable<Cursor> 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 resultSet = getResultsSet(key, makeResultsSet);
+
+    if (count == null)
+      count = DEFAULT_FETCH_COUNT;
+
+    ResultsResponse resultsResponse = new ResultsResponse();
+    resultsResponse.setSchema(resultSet.getSchema());
+    ArrayList<Object[]> rows = new ArrayList<Object[]>(count);
+    int read = resultSet.readRaw(rows, count);
+    resultsResponse.setRows(rows);
+    resultsResponse.setReadCount(read);
+    resultsResponse.setHasNext(resultSet.hasNext());
+//      resultsResponse.setSize(resultSet.size());
+    resultsResponse.setOffset(resultSet.getOffset());
+    return Response.ok(resultsResponse);
+  }
+
+  private static class ResultsResponse {
+    private ArrayList<ColumnDescription> schema;
+    private ArrayList<Object[]> rows;
+    private int readCount;
+    private boolean hasNext;
+    private long offset;
+
+    public void setSchema(ArrayList<ColumnDescription> schema) {
+      this.schema = schema;
+    }
+
+    public ArrayList<ColumnDescription> getSchema() {
+      return schema;
+    }
+
+    public void setRows(ArrayList<Object[]> rows) {
+      this.rows = rows;
+    }
+
+    public ArrayList<Object[]> getRows() {
+      return rows;
+    }
+
+    public void setReadCount(int readCount) {
+      this.readCount = readCount;
+    }
+
+    public int getReadCount() {
+      return 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;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/StoredOperationHandle.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/StoredOperationHandle.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/StoredOperationHandle.java
new file mode 100644
index 0000000..193b226
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/StoredOperationHandle.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.hive.resources.jobs;
+
+import org.apache.ambari.view.hive.persistence.utils.Indexed;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.hive.service.cli.thrift.THandleIdentifier;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+import org.apache.hive.service.cli.thrift.TOperationType;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Bean to represent TOperationHandle stored in DB
+ */
+public class StoredOperationHandle implements Indexed {
+  private boolean hasResultSet;
+  private double modifiedRowCount;
+  private int operationType;
+  private String guid;
+  private String secret;
+
+  private Integer jobId;
+
+  private Integer id;
+
+  public StoredOperationHandle() {}
+  public StoredOperationHandle(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
+      }
+    }
+  }
+
+
+  public static StoredOperationHandle buildFromTOperationHandle(TOperationHandle handle) {
+    StoredOperationHandle storedHandle = new StoredOperationHandle();
+    //bool hasResultSet
+    storedHandle.setHasResultSet(handle.isHasResultSet());
+    //optional double modifiedRowCount
+    storedHandle.setModifiedRowCount(handle.getModifiedRowCount());
+    //TOperationType operationType
+    storedHandle.setOperationType(handle.getOperationType().getValue());
+    //THandleIdentifier operationId
+    storedHandle.setGuid(Hex.encodeHexString(handle.getOperationId().getGuid()));
+    storedHandle.setSecret(Hex.encodeHexString(handle.getOperationId().getSecret()));
+    return storedHandle;
+  }
+
+  public TOperationHandle toTOperationHandle() {
+    TOperationHandle handle = new TOperationHandle();
+    handle.setHasResultSet(isHasResultSet());
+    handle.setModifiedRowCount(getModifiedRowCount());
+    handle.setOperationType(TOperationType.findByValue(getOperationType()));
+    THandleIdentifier identifier = new THandleIdentifier();
+    try {
+      identifier.setGuid(Hex.decodeHex(getGuid().toCharArray()));
+      identifier.setSecret(Hex.decodeHex(getSecret().toCharArray()));
+    } catch (DecoderException e) {
+      throw new ServiceFormattedException("Wrong identifer of OperationHandle is stored in DB");
+    }
+    handle.setOperationId(identifier);
+    return handle;
+  }
+
+  public boolean isHasResultSet() {
+    return hasResultSet;
+  }
+
+  public void setHasResultSet(boolean hasResultSet) {
+    this.hasResultSet = hasResultSet;
+  }
+
+  public double getModifiedRowCount() {
+    return modifiedRowCount;
+  }
+
+  public void setModifiedRowCount(double modifiedRowCount) {
+    this.modifiedRowCount = modifiedRowCount;
+  }
+
+  public int getOperationType() {
+    return operationType;
+  }
+
+  public void setOperationType(int operationType) {
+    this.operationType = operationType;
+  }
+
+  public String getGuid() {
+    return guid;
+  }
+
+  public void setGuid(String guid) {
+    this.guid = guid;
+  }
+
+  public String getSecret() {
+    return secret;
+  }
+
+  public void setSecret(String secret) {
+    this.secret = secret;
+  }
+
+  public Integer getJobId() {
+    return jobId;
+  }
+
+  public void setJobId(Integer jobId) {
+    this.jobId = jobId;
+  }
+
+  @Override
+  public Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(Integer id) {
+    this.id = id;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceItem.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceItem.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceItem.java
new file mode 100644
index 0000000..ddd9990
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.resources.resources;
+
+import org.apache.ambari.view.hive.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 Integer id;
+  private String owner;
+
+  public FileResourceItem() {}
+  public FileResourceItem(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(Integer 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;
+  }
+}


[03/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js
new file mode 100644
index 0000000..a2bebeb
--- /dev/null
+++ b/contrib/views/hive/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)return Gh(e,h)==f?h:(g=e

<TRUNCATED>

[05/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs
new file mode 100644
index 0000000..a870a0e
--- /dev/null
+++ b/contrib/views/hive/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"}}
+  {{text}}
+{{/modal-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-save.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
new file mode 100644
index 0000000..f327e3b
--- /dev/null
+++ b/contrib/views/hive/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="text" class="form-control"  value=text }}
+{{/modal-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/navbar.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/navbar.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/navbar.hbs
new file mode 100644
index 0000000..f8f6bcb
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/navbar.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"}}
+        {{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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/open-queries.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/open-queries.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/open-queries.hbs
new file mode 100644
index 0000000..ad1d9bd
--- /dev/null
+++ b/contrib/views/hive/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}}
+  {{render 'settings'}}
+  {{query-editor tables=selectedTables query=currentQuery.fileContent editor=view.editor highlightedText=highlightedText
+                 columnsNeeded="getColumnsForAutocomplete"}}
+{{/tabs-widget}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/queries.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/queries.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/queries.hbs
new file mode 100644
index 0000000..6187dfe
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/queries.hbs
@@ -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.
+}}
+
+<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>
+    {{#each query in this}}
+      <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>
+    {{/each}}
+  </tbody>
+</table>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/redirect.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/redirect.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/redirect.hbs
new file mode 100644
index 0000000..b776fd2
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/settings.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/settings.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/settings.hbs
new file mode 100644
index 0000000..15741802
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/settings.hbs
@@ -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.
+}}
+
+<span {{bind-attr class="showSettingsOverlay:active :fa :fa-gear :settings-toggle"}} {{action 'toggleOverlay'}}></span>
+
+{{#if showSettingsOverlay}}
+<div class="settings-container fadeIn">
+  <h3>Settings
+    <button class="btn btn-success btn-xs" {{action 'add'}}><i class="fa fa-plus"></i> Add</button>
+
+    <div class="checkbox btn btn-primary btn-xs runOnTez">
+        <label for="runOnTez">
+          {{input type="checkbox" checked=querySettings.runOnTez id="runOnTez"}} {{t "buttons.runOnTez"}}
+        </label>
+    </div>
+  </h3>
+
+  {{#each setting in querySettings.settings}}
+    <div class="setting">
+      <form class="form-inline">
+        <div class="form-group">
+          <div class="input-group">
+            <div class="input-group-addon">
+              {{input class="input-sm form-control" placeholder="Key" value=setting.key}}
+            </div>
+            <div class="input-group-addon">
+              {{input class="input-sm form-control" placeholder="Value" value=setting.value}}
+              <span class="fa fa-times-circle remove" {{action 'remove' setting}}></span>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+  {{/each}}
+
+</div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/udfs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/udfs.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/udfs.hbs
new file mode 100644
index 0000000..5bb8759
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/udfs.hbs
@@ -0,0 +1,112 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+
+<table class="table">
+  <thead>
+    <tr>
+      <th>{{t "columns.fileResource"}}</th>
+      {{#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>
+        <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}}
+      <tr>
+        <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=controller.fileResources
+                              selectedValue=udf.fileResource
+                              labelPath="name"
+                              defaultLabelTranslation="placeholders.select.file"
+                              itemAdded="addFileResource"
+                              itemEdited="editFileResource"
+                              itemRemoved="removeFileResource"
+                              canAdd=true
+                              canEdit=true}}
+            {{/if}}
+          {{else}}
+            {{#if udf.fileResource}}
+              {{udf.fileResource.name}}  ({{udf.fileResource.path}})
+            {{/if}}
+          {{/if}}
+        </td>
+        {{#each column in controller.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">
+                {{#each link in controller.links}}
+                  <li {{action 'executeAction' link}}><a>{{tb-helper link}}</a></li>
+                {{/each}}
+              </ul>
+            </div>
+          {{/if}}
+        </td>
+      </tr>
+    {{/each}}
+  </tbody>
+</table>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/transforms/date.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/transforms/date.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/transforms/date.js
new file mode 100644
index 0000000..716ab84
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
new file mode 100644
index 0000000..c9b1fda
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.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.
+ */
+
+import Ember from 'ember';
+
+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'
+    },
+
+    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 ',
+    insertUdfs: 'insert-udfs',
+    job: 'job',
+    jobs: 'jobs',
+    history: 'history',
+    savedQuery: 'saved-query',
+    database: 'database',
+    databases: 'databases',
+    openQueries: 'open-queries',
+    file: 'file',
+    fileResource: 'file-resource',
+    fileResources: 'file-resources',
+    loadedFiles: 'loaded-files',
+    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',
+    tables: 'tables',
+    columns: 'columns',
+    settings: 'settings'
+  },
+
+  statuses: {
+    unknown: "Unknown",
+    initialized: "Initialized",
+    running: "Running",
+    finished: "Finished",
+    canceled: "Canceled",
+    closed: "Closed",
+    error: "Error",
+    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: '0.0.1',
+    instance: 'Hive',
+    apiPrefix: '/api/v1/views/HIVE/versions/',
+    instancePrefix: '/instances/',
+    resourcePrefix: 'resources/'
+  },
+
+  settings: {
+    executionEngine: 'hive.execution.engine'
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
new file mode 100644
index 0000000..ab4f8e5
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.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';
+
+/* globals moment */
+
+export default Ember.Object.create({
+  isInteger: function (x) {
+    return (x^0) === x;
+  },
+
+  isDate: function(date) {
+    return moment(date).isValid();
+  },
+
+  regexes: {
+    allUppercase: /^[^a-z]*$/,
+    whitespaces: /^(\s*).*$/
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/views/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/views/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/history.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/history.js
new file mode 100644
index 0000000..8a914f0
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/history.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 default Ember.View.extend({
+  colspan: function () {
+    return this.get('controller.columns.length') + 1;
+  }.property('controller.columns')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/views/insert-udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/insert-udfs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/insert-udfs.js
new file mode 100644
index 0000000..70ed640
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/insert-udfs.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.View.extend({
+  tagName: 'insert-udfs'
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/views/navbar.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/navbar.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/navbar.js
new file mode 100644
index 0000000..0c535db
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/navbar.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';
+import constants from 'hive/utils/constants';
+
+export default Ember.View.extend({
+  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})
+  ])
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/big_tables.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/big_tables.js b/contrib/views/hive/src/main/resources/ui/hive-web/big_tables.js
new file mode 100644
index 0000000..9f3a317
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/bower.json b/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
new file mode 100644
index 0000000..a4c2aca
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
@@ -0,0 +1,27 @@
+{
+  "name": "hive",
+  "dependencies": {
+    "handlebars": "2.0.0",
+    "jquery": "^1.11.1",
+    "ember": "1.9.0",
+    "ember-data": "1.0.0-beta.11",
+    "ember-resolver": "~0.1.7",
+    "loader.js": "stefanpenner/loader.js#1.0.1",
+    "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3",
+    "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4",
+    "ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2",
+    "ember-qunit": "0.1.8",
+    "ember-qunit-notifications": "0.0.4",
+    "qunit": "~1.15.0",
+    "bootstrap": "~3.2.0",
+    "ember-i18n": "~2.9.0",
+    "blanket": "~1.1.5",
+    "jquery-ui": "~1.11.2",
+    "selectize": "~0.11.2",
+    "pretender": "0.1.0"
+  },
+  "resolutions": {
+    "handlebars": "2.0.0",
+    "ember": "1.9.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/config/environment.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/config/environment.js b/contrib/views/hive/src/main/resources/ui/hive-web/config/environment.js
new file mode 100644
index 0000000..86da93e
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/config/environment.js
@@ -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.
+ */
+
+/* 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
+      }
+    },
+
+    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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/package.json b/contrib/views/hive/src/main/resources/ui/hive-web/package.json
new file mode 100644
index 0000000..52e908a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/package.json
@@ -0,0 +1,45 @@
+{
+  "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.0"
+  },
+  "author": "",
+  "license": "MIT",
+  "devDependencies": {
+    "body-parser": "^1.2.0",
+    "bower": ">= 1.3.12",
+    "broccoli-asset-rev": "0.3.1",
+    "broccoli-sass": "^0.3.2",
+    "ember-cli": "0.1.2",
+    "ember-cli-blanket": "^0.2.2",
+    "ember-cli-content-security-policy": "0.3.0",
+    "ember-cli-font-awesome": "0.0.4",
+    "ember-cli-htmlbars": "^0.5.3",
+    "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.1.0",
+    "ember-cli-selectize": "0.0.7",
+    "ember-data": "1.0.0-beta.10",
+    "ember-dynamic-component": "0.0.1",
+    "ember-export-application-global": "^1.0.0",
+    "express": "^4.8.5",
+    "glob": "^4.0.5"
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/.jshintrc b/contrib/views/hive/src/main/resources/ui/hive-web/tests/.jshintrc
new file mode 100644
index 0000000..6ebf71a
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
new file mode 100644
index 0000000..a5580a9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.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.
+ */
+
+/* globals blanket */
+
+blanket.options({
+   filter: "//.*hive/.*/",
+   antifilter: ["//.*(tests).*/", "//.*(templates).*/"],
+   loaderExclusions: ['ember-cli-jquery-ui']
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
new file mode 100644
index 0000000..46a73f9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
@@ -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.
+ */
+
+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/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":"New Query",
+        "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 + '/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)];
+  });
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/resolver.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/resolver.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/resolver.js
new file mode 100644
index 0000000..f94998c
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/start-app.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/start-app.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/start-app.js
new file mode 100644
index 0000000..e029055
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/img/spinner.gif
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/img/spinner.gif b/contrib/views/hive/src/main/resources/ui/hive-web/tests/img/spinner.gif
new file mode 100644
index 0000000..39fcb67
Binary files /dev/null and b/contrib/views/hive/src/main/resources/ui/hive-web/tests/img/spinner.gif differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html b/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
new file mode 100644
index 0000000..6adbc89
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
@@ -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.
+-->
+<!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>
+      #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>
+  </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>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
new file mode 100644
index 0000000..5be4fdc
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
@@ -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.
+ */
+
+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() {
+  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-th').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-th').first();
+
+      click(targetTable);
+
+      andThen(function () {
+        console.log(find('.columns'));
+
+        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.');
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/history-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/history-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/history-test.js
new file mode 100644
index 0000000..35a950d
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
new file mode 100644
index 0000000..235a225
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/query-editor-test.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 { 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', function() {
+  expect(1);
+
+  visit("/");
+
+  Ember.run(function() {
+    find('.CodeMirror').get(0).CodeMirror.setValue('select count(*) from table1');
+  });
+
+  click('.execute-query');
+
+  andThen(function() {
+    ok(find('.query-process-results-panel .nav-tabs li:nth-child(2)').hasClass('active'), 'Results tab is visible');
+  });
+});
+
+
+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-dialog .modal-footer .btn-danger');
+});
+
+test('Can execute selection', function() {
+  expect(2);
+  visit('/');
+
+  var query1 = "select color from z;",
+      query2 = "select fruit from z;",
+      query = query1 + "\n" + query2,
+      editor;
+
+  Ember.run(function() {
+    editor = find('.CodeMirror').get(0).CodeMirror;
+    editor.setValue(query);
+    editor.setSelection({ line: 1, ch: 0 }, { line: 1, ch: 20 });
+  });
+  click('.execute-query');
+
+  andThen(function() {
+    equal(editor.getValue(), query, 'Editor value didn\'t change');
+    equal(editor.getSelection(), query2, 'Query 2 is selected');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/udfs-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
new file mode 100644
index 0000000..95a0043
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/test-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/test-helper.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/test-helper.js
new file mode 100644
index 0000000..53d9f9b
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/test-helper.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 resolver from './helpers/resolver';
+import {
+  setResolver
+} from 'ember-qunit';
+
+setResolver(resolver);
+
+document.write('<div id="ember-testing-container"><div id="ember-testing"></div></div>');
+
+QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'});
+var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible';
+document.getElementById('ember-testing-container').style.visibility = containerVisibility;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
new file mode 100644
index 0000000..da39a39
--- /dev/null
+++ b/contrib/views/hive/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 + '0.0.1' + constants.adapter.instancePrefix + 'Hive');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/file.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
new file mode 100644
index 0000000..ea70232
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
new file mode 100644
index 0000000..c7deabb
--- /dev/null
+++ b/contrib/views/hive/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.click();
+  });
+
+  equal(component.get('message.isExpanded'), true, 'isExpanded is set to true');
+
+  Ember.run(function() {
+    component.click();
+  });
+
+  equal(component.get('message.isExpanded'), false, 'isExpanded is set to false');
+});
+
+test('removeLater should be called on click', 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.click();
+  });
+
+  Ember.run(function() {
+    component.click();
+  });
+});
+
+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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
new file mode 100644
index 0000000..3af6d7d
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-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('collapsible-widget', 'CollapsibleWidgetComponent');
+
+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.append();
+
+  Ember.run(function() {
+    component.set('isExpanded', false);
+    component.send('toggle', {});
+   });
+});


[09/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceManager.java
new file mode 100644
index 0000000..31d9e23
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceManager.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.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(ViewContext context) {
+    super(FileResourceItem.class, context);
+  }
+
+  @Override
+  public FileResourceItem create(FileResourceItem object) {
+    return super.create(object);
+  }
+
+  @Override
+  public FileResourceItem read(Integer id) throws ItemNotFound {
+    return super.read(id);
+  }
+
+  @Override
+  public void delete(Integer 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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceProvider.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceProvider.java
new file mode 100644
index 0000000..5b9fc65
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceResourceProvider.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.resources;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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(context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public FileResourceItem getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<FileResourceItem> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    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, Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceService.java
new file mode 100644
index 0000000..2993280
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/resources/FileResourceService.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.resources;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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(context);
+    }
+    return resourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("id") String id) {
+    try {
+      FileResourceItem FileResourceItem = null;
+      FileResourceItem = getResourceManager().read(Integer.valueOf(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(Integer.valueOf(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, Integer.valueOf(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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQuery.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQuery.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQuery.java
new file mode 100644
index 0000000..fd75714
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.resources.savedQueries;
+
+import org.apache.ambari.view.hive.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 Integer id;
+  private String owner;
+
+  public SavedQuery() {}
+  public SavedQuery(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(Integer 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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceManager.java
new file mode 100644
index 0000000..a3c0f1b
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceManager.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.hive.resources.savedQueries;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive.utils.*;
+import org.apache.ambari.view.hive.utils.HdfsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Object that provides CRUD operations for query objects
+ */
+public class SavedQueryResourceManager extends PersonalCRUDResourceManager<SavedQuery> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(SavedQueryResourceManager.class);
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  private SavedQueryResourceManager(ViewContext context) {
+    super(SavedQuery.class, context);
+  }
+
+  //TODO: move all context-singletones to ContextController or smth like that
+  private static Map<String, SavedQueryResourceManager> viewSingletonObjects = new HashMap<String, SavedQueryResourceManager>();
+  public static SavedQueryResourceManager getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new SavedQueryResourceManager(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+  static Map<String, SavedQueryResourceManager> getViewSingletonObjects() {
+    return viewSingletonObjects;
+  }
+
+  @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-%d", 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 = HdfsUtil.findUnallocatedFileName(context, baseFileName, ".hql");
+    HdfsUtil.putStringToFile(context, newFilePath, "");
+
+    object.setQueryFile(newFilePath);
+    getStorage().store(SavedQuery.class, object);
+  }
+
+  @Override
+  public SavedQuery read(Integer 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(), context);
+      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(query.substring(0, (query.length() > 42)?42:query.length()));
+    }
+    getStorage().store(SavedQuery.class, savedQuery);
+  }
+
+  @Override
+  public List<SavedQuery> readAll(FilteringStrategy filteringStrategy) {
+    return super.readAll(filteringStrategy);
+  }
+
+  @Override
+  public void delete(Integer resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceProvider.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceProvider.java
new file mode 100644
index 0000000..20df9e6
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryResourceProvider.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.resources.savedQueries;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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 SavedQueryResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(SavedQueryResourceProvider.class);
+
+  protected synchronized SavedQueryResourceManager getResourceManager() {
+    return SavedQueryResourceManager.getInstance(context);
+  }
+
+  @Override
+  public SavedQuery getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<SavedQuery> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    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, Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryService.java
new file mode 100644
index 0000000..f6d5f41
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryService.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.hive.resources.savedQueries;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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 SavedQueryResourceManager.getInstance(context);
+  }
+
+  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 = null;
+      savedQuery = getResourceManager().read(Integer.valueOf(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(Integer.valueOf(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, Integer.valueOf(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);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class SavedQueryRequest {
+    public SavedQuery savedQuery;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDF.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDF.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDF.java
new file mode 100644
index 0000000..4a58e38
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.resources.udfs;
+
+import org.apache.ambari.view.hive.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 Integer fileResource;
+
+  private Integer id;
+  private String owner;
+
+  public UDF() {}
+  public UDF(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(Integer 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 Integer getFileResource() {
+    return fileResource;
+  }
+
+  public void setFileResource(Integer fileResource) {
+    this.fileResource = fileResource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceManager.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceManager.java
new file mode 100644
index 0000000..cb4264f
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceManager.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.udfs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.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(ViewContext context) {
+    super(UDF.class, context);
+  }
+
+  @Override
+  public UDF read(Integer 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(Integer resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceProvider.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceProvider.java
new file mode 100644
index 0000000..70994eb
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFResourceProvider.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.udfs;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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(context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public UDF getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<UDF> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    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, Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(Integer.valueOf(resourceId));
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFService.java
new file mode 100644
index 0000000..864d5b0
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/udfs/UDFService.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.udfs;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive.resources.resources.FileResourceItem;
+import org.apache.ambari.view.hive.resources.resources.FileResourceResourceManager;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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(context);
+    }
+    return resourceManager;
+  }
+
+  protected synchronized FileResourceResourceManager getFileResourceResourceManager() {
+    if (fileResourceResourceManager == null) {
+      fileResourceResourceManager = new FileResourceResourceManager(context);
+    }
+    return fileResourceResourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("id") String id) {
+    try {
+      UDF UDF = null;
+      UDF = getResourceManager().read(Integer.valueOf(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(Integer.valueOf(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, Integer.valueOf(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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/BadRequestFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/BadRequestFormattedException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/BadRequestFormattedException.java
new file mode 100644
index 0000000..0641af1
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/FilePaginator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/FilePaginator.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/FilePaginator.java
new file mode 100644
index 0000000..f27e1f9
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.utils;
+
+import org.apache.ambari.view.ViewContext;
+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 context View Context instance
+   */
+  public FilePaginator(String filePath, ViewContext context) {
+    this.filePath = filePath;
+    hdfsApi = HdfsApi.getInstance(context);
+  }
+
+  /**
+   * 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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsApi.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsApi.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsApi.java
new file mode 100644
index 0000000..9a120fa
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsApi.java
@@ -0,0 +1,399 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.utils;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.*;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.hdfs.DistributedFileSystem;
+import org.apache.hadoop.hdfs.web.WebHdfsFileSystem;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.json.simple.JSONArray;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * HDFS Business Delegate
+ */
+public class HdfsApi {
+  private Configuration conf = new Configuration();
+
+  private FileSystem fs;
+  private Map<String, String> params;
+
+  private UserGroupInformation ugi;
+  private final static Logger LOG =
+      LoggerFactory.getLogger(HdfsApi.class);
+
+  /**
+   * Constructor
+   * @param defaultFs hdfs uri
+   * @param username user.name
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public HdfsApi(final String defaultFs, String username, Map<String, String> params) throws IOException,
+      InterruptedException {
+    this.params = params;
+    Thread.currentThread().setContextClassLoader(null);
+    conf.set("fs.hdfs.impl", DistributedFileSystem.class.getName());
+    conf.set("fs.webhdfs.impl", WebHdfsFileSystem.class.getName());
+    conf.set("fs.file.impl", "org.apache.hadoop.fs.LocalFileSystem");
+    ugi = UserGroupInformation.createProxyUser(username, getProxyUser());
+    fs = ugi.doAs(new PrivilegedExceptionAction<FileSystem>() {
+      public FileSystem run() throws IOException {
+        return FileSystem.get(URI.create(defaultFs), conf);
+      }
+    });
+  }
+
+  private UserGroupInformation getProxyUser() throws IOException {
+    UserGroupInformation proxyuser;
+    if (params.containsKey("proxyuser")) {
+      proxyuser = UserGroupInformation.createRemoteUser(params.get("proxyuser"));
+    } else {
+      proxyuser = UserGroupInformation.getCurrentUser();
+    }
+
+    proxyuser.setAuthenticationMethod(getAuthenticationMethod());
+    return proxyuser;
+  }
+
+  private UserGroupInformation.AuthenticationMethod getAuthenticationMethod() {
+    UserGroupInformation.AuthenticationMethod authMethod;
+    if (params.containsKey("auth")) {
+      authMethod = UserGroupInformation.AuthenticationMethod.valueOf(params.get("auth"));
+    } else {
+      authMethod = UserGroupInformation.AuthenticationMethod.SIMPLE;
+    }
+    return authMethod;
+  }
+
+  /**
+   * List dir operation
+   * @param path path
+   * @return array of FileStatus objects
+   * @throws java.io.FileNotFoundException
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public FileStatus[] listdir(final String path) throws FileNotFoundException,
+      IOException, InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<FileStatus[]>() {
+      public FileStatus[] run() throws FileNotFoundException, Exception {
+        return fs.listStatus(new Path(path));
+      }
+    });
+  }
+
+  /**
+   * Get file status
+   * @param path path
+   * @return file status
+   * @throws java.io.IOException
+   * @throws java.io.FileNotFoundException
+   * @throws InterruptedException
+   */
+  public FileStatus getFileStatus(final String path) throws IOException,
+      FileNotFoundException, InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<FileStatus>() {
+      public FileStatus run() throws FileNotFoundException, IOException {
+        return fs.getFileStatus(new Path(path));
+      }
+    });
+  }
+
+  /**
+   * Make directory
+   * @param path path
+   * @return success
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public boolean mkdir(final String path) throws IOException,
+      InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        return fs.mkdirs(new Path(path));
+      }
+    });
+  }
+
+  /**
+   * Rename
+   * @param src source path
+   * @param dst destination path
+   * @return success
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public boolean rename(final String src, final String dst) throws IOException,
+      InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        return fs.rename(new Path(src), new Path(dst));
+      }
+    });
+  }
+
+  /**
+   * Delete
+   * @param path path
+   * @param recursive delete recursive
+   * @return success
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public boolean delete(final String path, final boolean recursive)
+      throws IOException, InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        return fs.delete(new Path(path), recursive);
+      }
+    });
+  }
+
+  /**
+   * Home directory
+   * @return home directory
+   * @throws Exception
+   */
+  public Path getHomeDir() throws Exception {
+    return ugi.doAs(new PrivilegedExceptionAction<Path>() {
+      public Path run() throws IOException {
+        return fs.getHomeDirectory();
+      }
+    });
+  }
+
+  /**
+   * Hdfs Status
+   * @return home directory
+   * @throws Exception
+   */
+  public FsStatus getStatus() throws Exception {
+    return ugi.doAs(new PrivilegedExceptionAction<FsStatus>() {
+      public FsStatus run() throws IOException {
+        return fs.getStatus();
+      }
+    });
+  }
+
+  /**
+   * Create file
+   * @param path path
+   * @param overwrite overwrite existent file
+   * @return output stream
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public FSDataOutputStream create(final String path, final boolean overwrite)
+      throws IOException, InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<FSDataOutputStream>() {
+      public FSDataOutputStream run() throws Exception {
+        return fs.create(new Path(path), overwrite);
+      }
+    });
+  }
+
+  /**
+   * Open file
+   * @param path path
+   * @return input stream
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public FSDataInputStream open(final String path) throws IOException,
+      InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<FSDataInputStream>() {
+      public FSDataInputStream run() throws Exception {
+        return fs.open(new Path(path));
+      }
+    });
+  }
+
+  /**
+   * Copy file
+   * @param src source path
+   * @param dest destination path
+   * @return success
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public void copy(final String src, final String dest) throws IOException,
+      InterruptedException {
+    boolean result = ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        return FileUtil.copy(fs, new Path(src), fs, new Path(dest), false, conf);
+      }
+    });
+    if (!result) {
+      throw new ServiceFormattedException("Can't copy source file from " + src + " to " + dest);
+    }
+  }
+
+  public boolean exists(final String newFilePath) throws IOException, InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        return fs.exists(new Path(newFilePath));
+      }
+    });
+  }
+
+  /**
+   * Converts a Hadoop permission into a Unix permission symbolic representation
+   * (i.e. -rwxr--r--) or default if the permission is NULL.
+   *
+   * @param p
+   *          Hadoop permission.
+   * @return the Unix permission symbolic representation or default if the
+   *         permission is NULL.
+   */
+  private static String permissionToString(FsPermission p) {
+    return (p == null) ? "default" : "-" + p.getUserAction().SYMBOL
+        + p.getGroupAction().SYMBOL + p.getOtherAction().SYMBOL;
+  }
+
+  /**
+   * Converts a Hadoop <code>FileStatus</code> object into a JSON array object.
+   * It replaces the <code>SCHEME://HOST:PORT</code> of the path with the
+   * specified URL.
+   * <p/>
+   *
+   * @param status
+   *          Hadoop file status.
+   * @return The JSON representation of the file status.
+   */
+
+  public static Map<String, Object> fileStatusToJSON(FileStatus status) {
+    Map<String, Object> json = new LinkedHashMap<String, Object>();
+    json.put("path", status.getPath().toString());
+    json.put("isDirectory", status.isDirectory());
+    json.put("len", status.getLen());
+    json.put("owner", status.getOwner());
+    json.put("group", status.getGroup());
+    json.put("permission", permissionToString(status.getPermission()));
+    json.put("accessTime", status.getAccessTime());
+    json.put("modificationTime", status.getModificationTime());
+    json.put("blockSize", status.getBlockSize());
+    json.put("replication", status.getReplication());
+    return json;
+  }
+
+  /**
+   * Converts a Hadoop <code>FileStatus</code> array into a JSON array object.
+   * It replaces the <code>SCHEME://HOST:PORT</code> of the path with the
+   * specified URL.
+   * <p/>
+   *
+   * @param status
+   *          Hadoop file status array.
+   * @return The JSON representation of the file status array.
+   */
+  @SuppressWarnings("unchecked")
+  public static JSONArray fileStatusToJSON(FileStatus[] status) {
+    JSONArray json = new JSONArray();
+    if (status != null) {
+      for (FileStatus s : status) {
+        json.add(fileStatusToJSON(s));
+      }
+    }
+    return json;
+  }
+
+
+  private static Map<String, HdfsApi> viewSingletonObjects = new HashMap<String, HdfsApi>();
+  /**
+   * Returns HdfsApi object specific to instance
+   * @param context View Context instance
+   * @return Hdfs business delegate object
+   */
+  public static HdfsApi getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), connectToHDFSApi(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public static void setInstance(ViewContext context, HdfsApi api) {
+    viewSingletonObjects.put(context.getInstanceName(), api);
+  }
+
+  public static HdfsApi connectToHDFSApi(ViewContext context) {
+    HdfsApi api = null;
+    Thread.currentThread().setContextClassLoader(null);
+
+    String defaultFS = context.getProperties().get("webhdfs.url");
+    if (defaultFS == null) {
+      String message = "webhdfs.url is not configured!";
+      LOG.error(message);
+      throw new MisconfigurationFormattedException("webhdfs.url");
+    }
+
+    try {
+      api = new HdfsApi(defaultFS, getHdfsUsername(context), getHdfsAuthParams(context));
+      LOG.info("HdfsApi connected OK");
+    } catch (IOException e) {
+      String message = "HdfsApi IO error: " + e.getMessage();
+      LOG.error(message);
+      throw new ServiceFormattedException(message, e);
+    } catch (InterruptedException e) {
+      String message = "HdfsApi Interrupted error: " + e.getMessage();
+      LOG.error(message);
+      throw new ServiceFormattedException(message, e);
+    }
+    return api;
+  }
+
+  private static Map<String, String> getHdfsAuthParams(ViewContext context) {
+    String auth = context.getProperties().get("webhdfs.auth");
+    Map<String, String> params = new HashMap<String, String>();
+    if (auth == null || auth.isEmpty()) {
+      auth = "auth=SIMPLE";
+    }
+    for(String param : auth.split(";")) {
+      String[] keyvalue = param.split("=");
+      if (keyvalue.length != 2) {
+        LOG.error("Can not parse authentication param " + param + " in " + auth);
+        continue;
+      }
+      params.put(keyvalue[0], keyvalue[1]);
+    }
+    return params;
+  }
+
+  public static String getHdfsUsername(ViewContext context) {
+    String userName = context.getProperties().get("webhdfs.username");
+    if (userName == null || userName.compareTo("null") == 0 || userName.compareTo("") == 0)
+      userName = context.getUsername();
+    return userName;
+  }
+
+  public static void dropAllConnections() {
+    viewSingletonObjects.clear();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsUtil.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsUtil.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsUtil.java
new file mode 100644
index 0000000..c1c5495
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/HdfsUtil.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.hive.utils;
+
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class HdfsUtil {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(HdfsUtil.class);
+
+  /**
+   * Write string to file with overwriting
+   * @param filePath path to file
+   * @param content new content of file
+   */
+  public static void putStringToFile(ViewContext context, String filePath, String content) {
+    HdfsApi hdfs = HdfsApi.getInstance(context);
+
+    FSDataOutputStream stream;
+    try {
+      stream = hdfs.create(filePath, true);
+      stream.writeBytes(content);
+      stream.close();
+    } catch (IOException e) {
+      throw new ServiceFormattedException("Could not write file " + filePath, e);
+    } catch (InterruptedException e) {
+      throw new ServiceFormattedException("Could not write file " + filePath, e);
+    }
+  }
+
+
+  /**
+   * Increment index appended to filename until find first unallocated file
+   * @param fullPathAndFilename path to file and prefix for filename
+   * @param extension file extension
+   * @return if fullPathAndFilename="/tmp/file",extension=".txt" then filename will be like "/tmp/file_42.txt"
+   */
+  public static String findUnallocatedFileName(ViewContext context, String fullPathAndFilename, String extension) {
+    HdfsApi hdfs = HdfsApi.getInstance(context);
+
+    int triesCount = 0;
+    String newFilePath;
+    boolean isUnallocatedFilenameFound;
+
+    try {
+      do {
+        newFilePath = String.format(fullPathAndFilename + "%s" + extension, (triesCount == 0) ? "" : "_" + triesCount);
+        LOG.debug("Trying to find free filename " + newFilePath);
+
+        isUnallocatedFilenameFound = !hdfs.exists(newFilePath);
+        if (isUnallocatedFilenameFound) {
+          LOG.debug("File created successfully!");
+        }
+
+        triesCount += 1;
+      } while (!isUnallocatedFilenameFound);
+    } catch (IOException e) {
+      throw new ServiceFormattedException("Error in creation: " + e.toString(), e);
+    } catch (InterruptedException e) {
+      throw new ServiceFormattedException("Error in creation: " + e.toString(), e);
+    }
+
+    return newFilePath;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/MisconfigurationFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/MisconfigurationFormattedException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/MisconfigurationFormattedException.java
new file mode 100644
index 0000000..314b00b
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/NotFoundFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/NotFoundFormattedException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/NotFoundFormattedException.java
new file mode 100644
index 0000000..91b11cf
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/ServiceFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/ServiceFormattedException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/ServiceFormattedException.java
new file mode 100644
index 0000000..19b324c
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/ServiceFormattedException.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.hive.utils;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+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.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(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;
+    }
+    return status;
+  }
+
+  protected static Response errorEntity(String message, Throwable e, int status, String header) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", message);
+    String trace = null;
+    if (e != null)
+      trace = ExceptionUtils.getStackTrace(e);
+    response.put("trace", trace);
+    response.put("status", status);
+
+    if(message != null) LOG.error(message);
+    if(trace != null) LOG.debug(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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/.gitignore b/contrib/views/hive/src/main/resources/ui/hive-web/.gitignore
new file mode 100644
index 0000000..043148a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/.gitignore
@@ -0,0 +1,35 @@
+# 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/
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc b/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
new file mode 100644
index 0000000..c1fe863
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
@@ -0,0 +1,32 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise"
+  ],
+  "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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js b/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.js
new file mode 100644
index 0000000..db65f1f
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/Brocfile.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.
+ */
+
+/* global require, module */
+
+var EmberApp = require('ember-cli/lib/broccoli/ember-app');
+
+var app = new EmberApp({
+  'ember-cli-selectize': {
+    //valid values are `default`, `bootstrap2`, `bootstrap3` or false
+    'theme': 'bootstrap3'
+  },
+  hinting: false
+});
+
+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');
+
+module.exports = app.toTree();

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


[08/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/application.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/application.js
new file mode 100644
index 0000000..e838a3d
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/application.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 DS from 'ember-data';
+import constants from 'hive/utils/constants';
+
+export default DS.RESTAdapter.extend({
+  headers: {
+    "X-Requested-By": "ambari"
+  },
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/database.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/database.js
new file mode 100644
index 0000000..cdbd43b
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/adapters/file.js
new file mode 100644
index 0000000..47894c1
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/app.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/app.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/app.js
new file mode 100644
index 0000000..f35a5a3
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
new file mode 100644
index 0000000..fd8c1d7
--- /dev/null
+++ b/contrib/views/hive/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({
+  click: function () {
+    this.toggleProperty('message.isExpanded');
+
+    if (!this.get('message.isExpanded')) {
+      this.sendAction('removeLater', this.get('message'));
+    }
+  },
+
+  actions: {
+    remove: function () {
+      this.sendAction('removeMessage', this.get('message'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
new file mode 100644
index 0000000..4425b59
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/collapsible-widget.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.Component.extend({
+  tagName: 'collapsible',
+
+  actions: {
+    toggle: function () {
+      this.toggleProperty('isExpanded');
+
+      if (this.get('isExpanded')) {
+        this.sendAction('expanded', this.get('heading'), this.get('toggledParam'));
+      }
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/column-filter-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/column-filter-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/column-filter-widget.js
new file mode 100644
index 0000000..2622d4b
--- /dev/null
+++ b/contrib/views/hive/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) {
+        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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/date-range-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/date-range-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/date-range-widget.js
new file mode 100644
index 0000000..790cb35
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/date-range-widget.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.
+ */
+
+ /* 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'),
+
+  didInsertElement: function () {
+    var self = this;
+
+    if (!this.get('dateRange.min') && !this.get('dateRange.max')) {
+      this.set('dateRange.max', new Date());
+    }
+
+    if (!this.get('dateRange.from') && !this.get('dateRange.to')) {
+      this.set('dateRange.from', this.get('dateRange.min'));
+      this.set('dateRange.to', this.get('dateRange.max'));
+    }
+
+    this.$(".fromDate").datepicker({
+      defaultDate: this.get("dateRange.from"),
+      onSelect: function (selectedDate) {
+        self.$(".toDate").datepicker("option", "minDate", selectedDate);
+        self.set('dateRange.from', new Date(selectedDate));
+        self.sendAction('rangeChanged', self.get('dateRange'));
+      }
+    });
+
+    this.$(".toDate").datepicker({
+      defaultDate: this.get('dateRange.to'),
+      onSelect: function (selectedDate) {
+        self.$(".fromDate").datepicker("option", "maxDate", selectedDate);
+        self.set('dateRange.to', new Date(selectedDate + " 23:59"));
+        self.sendAction('rangeChanged', self.get('dateRange'));
+      }
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/expander-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/expander-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/expander-widget.js
new file mode 100644
index 0000000..d46a490
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/expander-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: 'expander',
+
+  actions: {
+    toggle: function () {
+      this.toggleProperty('isExpanded');
+      this.$('.accordion-body').toggle(200);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/extended-input.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/extended-input.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/extended-input.js
new file mode 100644
index 0000000..ee2161c
--- /dev/null
+++ b/contrib/views/hive/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');
+  },
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-widget.js
new file mode 100644
index 0000000..b9179bb
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/modal-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, {
+  show: function() {
+    this.$('.modal').modal().on('hidden.bs.modal', function () {
+      this.sendAction('close');
+    }.bind(this));
+  }.on('didInsertElement'),
+
+  actions: {
+    ok: function () {
+      this.$('.modal').modal('hide');
+      this.sendAction('ok');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/no-bubbling.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/no-bubbling.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/no-bubbling.js
new file mode 100644
index 0000000..4b723b1
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.js
new file mode 100644
index 0000000..ad98beb
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/number-range-widget.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';
+
+export default Ember.Component.extend({
+  didInsertElement: function () {
+    var self = this;
+
+    var slider;
+
+    this.$(function() {
+      if (!self.get('numberRange.from') && !self.get('numberRange.to')) {
+        self.get('numberRange').set('from', self.get('numberRange.min'));
+        self.get('numberRange').set('to', self.get('numberRange.max'));
+      }
+
+      slider = self.$( ".slider" ).slider({
+        range: true,
+        min: self.get('numberRange.min'),
+        max: self.get('numberRange.max'),
+        units: self.get('numberRange.units'),
+        values: [ self.get('numberRange.from'), self.get('numberRange.to') ],
+        slide: function (event, ui) {
+          self.set('numberRange.from', ui.values[0]);
+          self.set('numberRange.to', ui.values[1]);
+        },
+
+        change: function () {
+          self.sendAction('rangeChanged', self.get('numberRange'));
+        }
+      });
+    });
+
+    this.set('slider', slider);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/panel-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/panel-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/panel-widget.js
new file mode 100644
index 0000000..1f41a43
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/popover-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/popover-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/popover-widget.js
new file mode 100644
index 0000000..e1bd4c5
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/popover-widget.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.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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/progress-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/progress-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/progress-widget.js
new file mode 100644
index 0000000..2a86ee7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/progress-widget.js
@@ -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.
+ */
+
+// this component is a work in progress
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  formattedStages: Ember.ArrayProxy.create({ content: [] }),
+
+  formatStages: function() {
+    var formattedStages = this.get('formattedStages');
+    var stages = this.get('stages');
+    var currentStage;
+
+    stages.forEach(function(stage) {
+      currentStage = formattedStages.findBy('name', stage.get('name'));
+
+      if(currentStage) {
+        currentStage.set('progress', 'width: %@%'.fmt(stage.get('value')))
+      } else {
+        formattedStages.pushObject(Ember.Object.create({
+          name: stage.get('name'),
+          className: stage.get('className'),
+          progress: 'width: %@%'.fmt(stage.get('value'))
+        }));
+      }
+    });
+  }.observes('stages.@each.value').on('init')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-editor.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-editor.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-editor.js
new file mode 100644
index 0000000..01ba37e
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/query-editor.js
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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');
+
+    if (editor.getValue() !== query) {
+      editor.setValue(query || '');
+    }
+  }.observes('query')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/select-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/select-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/select-widget.js
new file mode 100644
index 0000000..8bd7a22
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tabs-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tabs-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tabs-widget.js
new file mode 100644
index 0000000..2a898f5
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tabs-widget.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';
+
+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);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tree-view.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tree-view.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/tree-view.js
new file mode 100644
index 0000000..cd63f52
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
new file mode 100644
index 0000000..8226c9c
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/typeahead-widget.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 Typeahead from 'ember-cli-selectize/components/ember-selectize';
+import Ember from 'ember';
+
+export default Typeahead.extend({
+  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));
+  },
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.js
new file mode 100644
index 0000000..be70566
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/alerts.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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.ArrayController.extend({
+  pushObject: function (object) {
+    object.typeClass = 'alert-' + object.type;
+    this._super(object);
+    this.removeLater(object);
+  },
+
+  removeLater: function (object) {
+    var self = this;
+
+    Ember.run.later(function() {
+      if (!object.isExpanded) {
+        self.removeObject(object);
+      }
+    }, 5000);
+  },
+
+  actions: {
+    remove: function (message) {
+      this.removeObject(message);
+    },
+
+    removeLater: function (message) {
+      this.removeLater(message);
+    }
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/columns.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/columns.js
new file mode 100644
index 0000000..38d1b95
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/columns.js
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ObjectController.extend({
+  pageCount: 10,
+
+  init: function () {
+    this._super();
+
+    var databaseAdapter = this.container.lookup('adapter:database');
+    var baseUrl = databaseAdapter.buildURL() + '/' +
+                  databaseAdapter.pathForType(constants.namingConventions.database) + '/';
+
+    this.set('baseUrl', baseUrl);
+  },
+
+  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';
+
+    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]
+          });
+        });
+
+        defer.resolve({
+          columns: columns,
+          hasNext: data.hasNext
+        });
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  getColumns: function (databaseName, tableName) {
+    var defer = Ember.RSVP.defer();
+
+    var url = this.get('baseUrl') +
+              databaseName +
+              '/table/' +
+              tableName;
+
+    Ember.$.getJSON(url).then(function (data) {
+      Ember.run(function () {
+        var columns = data.columns.map(function (column) {
+          return Ember.Object.create({
+            name: column[0],
+            type: column[1]
+          });
+        });
+
+        defer.resolve(columns);
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
new file mode 100644
index 0000000..6a259ba
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
@@ -0,0 +1,354 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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({
+  pageCount: 10,
+
+  needs: [ constants.namingConventions.tables,
+           constants.namingConventions.columns,
+           constants.namingConventions.openQueries ],
+
+  openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+  dbTables: Ember.computed.alias('controllers.' + constants.namingConventions.tables),
+  dbColumns: Ember.computed.alias('controllers.' + constants.namingConventions.columns),
+
+  _handleTablesError: function (err) {
+    this.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.get.tables");
+    this.set('isLoading', false);
+  },
+
+  _handleColumnsError: function (err) {
+    this.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.get.columns");
+    this.set('isLoading', false);
+  },
+
+  init: function () {
+    this._super();
+
+    var databaseAdapter = this.container.lookup('adapter:database');
+    var baseUrl = databaseAdapter.buildURL() + '/' +
+                  databaseAdapter.pathForType(constants.namingConventions.database) + '/';
+
+    this.set('baseUrl', baseUrl);
+    this.set('tableSearchResults', Ember.Object.create());
+
+    this.set('tabs', Ember.ArrayProxy.create({ content: Ember.A([
+      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
+      })
+    ])}));
+  },
+
+  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,
+        database = this.get('selectedDatabase');
+
+    //if no selected database or database has already fully loaded tables
+    if (!database || (database.tables && !database.get('hasNext'))) {
+      return;
+    }
+
+    this.set('isLoading', true);
+
+    this.get('dbTables').getTables(database.get('name')).then(function (tables) {
+      var mappedTables = {};
+
+      //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;
+
+      tables.forEach(function (table) {
+        mappedTables[table.name] = [];
+      });
+
+      self.set('openQueries.selectedTables', mappedTables);
+      self.set('isLoading', false);
+    }, function (err) {
+      self._handleTablesError(err);
+    });
+  }.observes('selectedDatabase'),
+
+  getNextColumnPage: function (database, table) {
+    var self = this;
+
+    this.set('isLoading', true);
+
+    if (!table.columns) {
+      table.columns = [];
+      table.set('visibleColumns', []);
+    }
+
+    this.get('dbColumns').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._handleColumnsError(err);
+    });
+  },
+
+  getNextTablePage: function (database) {
+    var self = this;
+
+    this.set('isLoading', true);
+
+    if (!database.tables) {
+      database.tables = [];
+      database.set('visibleTables', []);
+    }
+
+    this.get('dbTables').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._handleTablesError(err);
+    });
+  },
+
+  getAllColumns: function (tableName) {
+    var defer = Ember.RSVP.defer();
+    var self = this;
+    var database = this.get('selectedDatabase');
+    var table = database.get('tables').findBy('name', tableName);
+
+    //if all the columns were already loaded for this table, do not get them again.
+    if (table.columns && !table.get('hasNext')) {
+      defer.resolve();
+    } else {
+      this.set('isLoading', true);
+
+      this.get('dbColumns').getColumns(database.get('name'), tableName).then(function (columns) {
+        table.columns = columns;
+        table.set('hasNext', false);
+
+        self.get('openQueries.selectedTables')[tableName] = columns.mapProperty('name');
+        self.set('isLoading', false);
+
+        defer.resolve();
+      }, function (err) {
+        self._handleColumnsError(err);
+        defer.reject(err);
+      });
+    }
+
+    return defer.promise;
+  },
+
+  actions: {
+    getTables: function (dbName) {
+      var database = this.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');
+
+      resultsTab.set('visible', true);
+      this.set('selectedTab', resultsTab);
+      this.set('columnSearchTerm', '');
+      this.set('isLoading', true);
+
+      this.get('dbTables').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._handleTablesError(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');
+
+      this.set('selectedTab', resultsTab);
+
+      this.set('isLoading', true);
+
+      tables.forEach(function (table) {
+        self.get('dbColumns').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._handleColumnsError(err);
+        });
+      });
+    },
+
+    showMoreResultTables: function () {
+      var self = this,
+          database = this.get('selectedDatabase'),
+          tableSearchResults = this.get('tableSearchResults'),
+          searchTerm = this.get('tableSearchTerm');
+
+      this.set('isLoading', true);
+
+      this.get('dbTables').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('dbColumns').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._handleColumnsError(err);
+            });
+          });
+        } else {
+          self.set('isLoading', false);
+        }
+      }, function (err) {
+        self._handleTablesError(err);
+      });
+    },
+
+    showMoreResultColumns: function (table) {
+      var self = this;
+
+      this.set('isLoading', true);
+
+      this.get('dbColumns').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._handleColumnsError(err);
+      });
+    }
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/file-resources.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/file-resources.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/file-resources.js
new file mode 100644
index 0000000..578fa67
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/file-resources.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.ArrayController.extend({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/history.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/history.js
new file mode 100644
index 0000000..157b917
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/history.js
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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, {
+  itemController: constants.namingConventions.job,
+
+  sortAscending: true,
+  sortProperties: ['dateSubmitted'],
+
+  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',
+        classBinding: 'status'
+      }),
+      Ember.Object.create({
+        caption: 'columns.date',
+        property: 'dateSubmitted',
+        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';
+      });
+
+      minDuration = Math.min.apply(Math, this.get('history').map(function (item) {
+        return item.get(durationColumn.get('property'));
+      }));
+
+      maxDuration = Math.max.apply(Math, this.get('history').map(function (item) {
+        return item.get(durationColumn.get('property'));
+      }));
+
+      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';
+      });
+
+      minDate = Math.min.apply(Math, this.get('history').map(function (item) {
+        return item.get(dateColumn.get('property'));
+      }));
+
+      maxDate = Math.max.apply(Math, this.get('history').map(function (item) {
+        return item.get(dateColumn.get('property'));
+      }));
+
+      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) {
+      var self = this,
+          id = job.get('id');
+
+      job.destroyRecord().then(function () {
+        self.store.find(constants.namingConventions.job, id);
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
new file mode 100644
index 0000000..6f93b11
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
@@ -0,0 +1,475 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.openQueries,
+           constants.namingConventions.databases,
+           constants.namingConventions.udfs,
+           constants.namingConventions.jobLogs,
+           constants.namingConventions.jobResults,
+           constants.namingConventions.jobExplain,
+           constants.namingConventions.settings
+  ],
+
+  openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+  databases: Ember.computed.alias('controllers.' + constants.namingConventions.databases),
+  udfs: Ember.computed.alias('controllers.' + constants.namingConventions.udfs + '.udfs'),
+  logs: Ember.computed.alias('controllers.' + constants.namingConventions.jobLogs),
+  results: Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+  explain: Ember.computed.alias('controllers.' + constants.namingConventions.jobExplain),
+  settings: Ember.computed.alias('controllers.' + constants.namingConventions.settings),
+
+  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'),
+
+  parseQueryParams: 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);
+  }.observes('openQueries.currentQuery.fileContent'),
+
+  _executeQuery: function (shouldExplain) {
+    var queryId,
+        self = this,
+        query,
+        finalQuery,
+        job,
+        originalModel = this.get('model');
+
+    job = this.store.createRecord(constants.namingConventions.job, {
+      title: originalModel.get('title'),
+      dataBase: this.get('databases.selectedDatabase.name')
+    });
+
+    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);
+
+    finalQuery = this.buildQuery(query, shouldExplain);
+    finalQuery = this.bindQueryParams(finalQuery);
+    finalQuery = this.prependQuerySettings(finalQuery);
+
+    job.set('forcedContent', finalQuery);
+
+    return this.saveQuery(job, originalModel);
+  },
+
+  saveQuery: function (job, originalModel) {
+    var defer = Ember.RSVP.defer(),
+        self = this,
+        openQueries = this.get('openQueries');
+
+    var handleError = function (err) {
+      originalModel.set('isRunning', undefined);
+      defer.reject(err);
+    };
+
+    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 () {
+        //reset flag on the original model
+        originalModel.set('isRunning', undefined);
+
+        defer.resolve(job);
+      }, function (err) {
+        handleError(err);
+      });
+
+      self.get('settings').updateSettingsId(originalModel.get('id'), job.get('id'));
+    }, function (err) {
+      handleError(err);
+    });
+
+    return defer.promise;
+  },
+
+  prependQuerySettings: function (query) {
+    var settings = this.get('settings').getSettingsString();
+
+    if (settings.length) {
+      return settings + "\n\n" + query;
+    }
+
+    return query;
+  },
+
+  buildQuery: function (query, shouldExplain) {
+    var selections = this.get('openQueries.highlightedText'),
+        isQuerySelected = selections && selections[0] !== "",
+        queryComponents = this.extractComponents(query.get('fileContent')),
+        finalQuery = '',
+        queries;
+
+    if (isQuerySelected) {
+      queries = selections.map(function (s) {
+        return s.replace(";", "");
+      });
+    } else {
+      queries = queryComponents.queryString.split(';');
+      queries = queries.filter(Boolean);
+    }
+
+    queries = queries.map(function (query) {
+      var explainIndex = query.indexOf(constants.namingConventions.explainPrefix);
+
+      if (shouldExplain) {
+        if (query.indexOf(constants.namingConventions.explainPrefix) === -1) {
+          return constants.namingConventions.explainPrefix + query;
+        }
+
+        return query;
+      } else {
+        if (query.indexOf(constants.namingConventions.explainPrefix) > -1) {
+          return query.replace(constants.namingConventions.explainPrefix, '');
+        }
+
+        return query;
+      }
+    });
+
+    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;
+  },
+
+  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;
+  },
+
+  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
+      })
+    ])}));
+  },
+
+  displayJobTabs: function () {
+    return this.get('content.constructor.typeKey') === constants.namingConventions.job;
+  }.property('content'),
+
+  modelChanged: function () {
+    var self = this;
+    var content = this.get('content');
+    var openQueries = this.get('openQueries');
+
+    //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 (content.get('constructor.typeKey') === constants.namingConventions.job) {
+        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 (this.get('content.status') !== constants.statuses.finished) {
+      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 (this.get('content.status') === constants.statuses.finished && 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'),
+            href: this.get('csvUrl')
+          })
+        );
+      }
+    }
+
+    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 () {
+    var job = this.get('content');
+
+    if (job.get('status') !== constants.statuses.finished) {
+      return;
+    }
+
+    var self = this;
+
+    var file = "/tmp/" + job.get('id') + ".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 (response) {
+      self.send('addAlert', constants.alerts.error, response.message, "alerts.errors.save.results");
+    });
+  },
+
+  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 (response.status !== constants.results.statuses.terminated) {
+          self.pollSaveToHDFS(response);
+        } else {
+          self.set('content.isRunning', false);
+        }
+      }, function (response) {
+        self.send('addAlert', constants.alerts.error, response.message, "alerts.errors.save.results");
+      });
+    }, 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);
+  },
+
+  actions: {
+    saveToHDFS: function () {
+      this.set('content.isRunning', true);
+      this.saveToHDFS();
+    },
+
+    insertUdf: function (item) {
+      var query = this.get('openQueries').getQueryForModel(this.get('model'));
+
+      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 () {
+        var model = this.store.createRecord(constants.namingConventions.savedQuery, {
+          dataBase: this.get('databases.selectedDatabase.name'),
+          title: 'New Query',
+          type: constants.namingConventions.savedQuery,
+          queryFile: '',
+          id: 'fixture_' + idCounter
+        });
+
+        idCounter++;
+
+        this.transitionToRoute(constants.namingConventions.subroutes.savedQuery, model);
+      };
+    }()),
+
+    saveQuery: function () {
+      var self = this,
+          wasNew = this.get('model.isNew'),
+          defer = Ember.RSVP.defer();
+
+      this.send('openModal', 'modal-save', {
+        heading: "modals.save.heading",
+        text: this.get('content.title'),
+        defer: defer
+      });
+
+      defer.promise.then(function (text) {
+        self.get('content').set('title', text);
+
+        self.get('openQueries').save(self.get('content')).then(function () {
+          if (wasNew) {
+            self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, self.get('model.id'));
+          }
+        });
+      });
+    },
+
+    executeQuery: function () {
+      var self = this;
+      var subroute;
+
+      this._executeQuery().then(function (job) {
+        if (job.get('status') !== constants.statuses.finished) {
+          subroute = constants.namingConventions.subroutes.jobLogs;
+        } else {
+          subroute = constants.namingConventions.subroutes.jobResults;
+        }
+
+        self.get('openQueries').updateTabSubroute(job, subroute);
+
+        self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+      }, function (err) {
+        self.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.save.query");
+      });
+    },
+
+    explainQuery: function () {
+      var self = this;
+
+      this._executeQuery(true).then(function (job) {
+        self.get('openQueries').updateTabSubroute(job, constants.namingConventions.subroutes.jobExplain);
+
+        self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+      }, function (err) {
+        self.send('addAlert', constants.alerts.error, err.responseText, "alerts.errors.save.query");
+      });
+    }
+  }
+});


[02/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css
new file mode 100644
index 0000000..68c67b1
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css
new file mode 100644
index 0000000..924e638
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js
new file mode 100644
index 0000000..27b770b
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js
new file mode 100644
index 0000000..522f9e8
--- /dev/null
+++ b/contrib/views/hive/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)};
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/view.xml b/contrib/views/hive/src/main/resources/view.xml
new file mode 100644
index 0000000..b936c6d
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/view.xml
@@ -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.
+-->
+<view>
+    <name>HIVE</name>
+    <label>Hive</label>
+    <version>0.0.1</version>
+
+    <!-- HDFS Configs -->
+    <parameter>
+        <name>webhdfs.url</name>
+        <description>WebHDFS FileSystem URI (example: webhdfs://namenode:50070)</description>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>webhdfs.username</name>
+        <description>User and doAs for proxy user for HDFS</description>
+        <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>webhdfs.auth</name>
+        <description>Semicolon-separated authentication configs. Default: auth=SIMPLE</description>
+        <required>false</required>
+    </parameter>
+
+    <!-- General Configs -->
+
+    <parameter>
+        <name>dataworker.username</name>
+        <description>The username (defaults to ViewContext username)</description>
+        <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>scripts.dir</name>
+        <description>HDFS directory path to store Hive scripts (example: /users/${username})</description>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>jobs.dir</name>
+        <description>HDFS directory path to store Hive job status (example: /users/${username})</description>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>hive.host</name>
+        <description>HiveServer2 hostname or IP (example: 127.0.0.1)</description>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>hive.port</name>
+        <description>HiveServer2 Thrift port (example: 10000)</description>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>hive.auth</name>
+        <description>Semicolon-separated authentication configs. Default: auth=NOSASL</description>
+        <required>false</required>
+    </parameter>
+
+    <resource>
+        <name>savedQuery</name>
+        <plural-name>savedQueries</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hive.resources.savedQueries.SavedQuery</resource-class>
+        <provider-class>org.apache.ambari.view.hive.resources.savedQueries.SavedQueryResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive.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.hive.resources.resources.FileResourceItem</resource-class>
+        <provider-class>org.apache.ambari.view.hive.resources.resources.FileResourceResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive.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.hive.resources.udfs.UDF</resource-class>
+        <provider-class>org.apache.ambari.view.hive.resources.udfs.UDFResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive.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.hive.resources.jobs.JobImpl</resource-class>
+        <provider-class>org.apache.ambari.view.hive.resources.jobs.JobResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive.resources.jobs.JobService</service-class>
+    </resource>
+
+    <resource>
+        <name>file</name>
+        <service-class>org.apache.ambari.view.hive.resources.files.FileService</service-class>
+    </resource>
+
+    <resource>
+        <name>ddl</name>
+        <service-class>org.apache.ambari.view.hive.resources.browser.HiveBrowserService</service-class>
+    </resource>
+
+    <resource>
+        <name>hive</name>
+        <service-class>org.apache.ambari.view.hive.HelpService</service-class>
+    </resource>
+
+    <persistence>
+        <entity>
+            <class>org.apache.ambari.view.hive.persistence.DataStoreStorage$SmokeTestEntity</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.resources.jobs.JobImpl</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.resources.jobs.StoredOperationHandle</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.resources.savedQueries.SavedQuery</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.resources.udfs.UDF</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.resources.resources.FileResourceItem</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive.TestBean</class>
+            <id-property>id</id-property>
+        </entity>
+    </persistence>
+</view>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java
new file mode 100644
index 0000000..f38d0e9
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.hadoop.fs.FileUtil;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+
+public abstract class BaseHiveTest {
+  protected ViewResourceHandler handler;
+  protected ViewContext context;
+  protected static File hiveStorageFile;
+  protected static File baseDir;
+  protected Map<String, String> properties;
+
+  protected static String DATA_DIRECTORY = "./target/HiveTest";
+
+  @BeforeClass
+  public static void startUp() throws Exception {
+    File baseDir = new File(DATA_DIRECTORY)
+        .getAbsoluteFile();
+    FileUtil.fullyDelete(baseDir);
+  }
+
+  @AfterClass
+  public static void shutDown() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    handler = createNiceMock(ViewResourceHandler.class);
+    context = createNiceMock(ViewContext.class);
+
+    properties = new HashMap<String, String>();
+    baseDir = new File(DATA_DIRECTORY)
+        .getAbsoluteFile();
+    hiveStorageFile = new File("./target/HiveTest/storage.dat")
+        .getAbsoluteFile();
+
+    properties.put("dataworker.storagePath", hiveStorageFile.toString());
+    properties.put("scripts.dir", "/tmp/.hiveQueries");
+    properties.put("jobs.dir", "/tmp/.hiveJobs");
+
+    setupProperties(properties, baseDir);
+
+    expect(context.getProperties()).andReturn(properties).anyTimes();
+    expect(context.getUsername()).andReturn("ambari-qa").anyTimes();
+    expect(context.getInstanceName()).andReturn("MyHive").anyTimes();
+
+    replay(handler, context);
+  }
+
+  protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+
+  }
+
+  protected static <T> T getService(Class<T> clazz,
+                                    final ViewResourceHandler viewResourceHandler,
+                                    final ViewContext viewInstanceContext) {
+    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(ViewResourceHandler.class).toInstance(viewResourceHandler);
+        bind(ViewContext.class).toInstance(viewInstanceContext);
+      }
+    });
+    return viewInstanceInjector.getInstance(clazz);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/HDFSTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/HDFSTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/HDFSTest.java
new file mode 100644
index 0000000..0ee8eb3
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/HDFSTest.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import java.io.File;
+import java.util.Map;
+
+public abstract class HDFSTest extends BaseHiveTest {
+  protected static MiniDFSCluster hdfsCluster;
+  protected static String hdfsURI;
+
+  @BeforeClass
+  public static void startUp() throws Exception {
+    BaseHiveTest.startUp(); // super
+    File hdfsDir = new File("./target/HiveTest/hdfs/")
+        .getAbsoluteFile();
+    FileUtil.fullyDelete(hdfsDir);
+
+    Configuration conf = new Configuration();
+    conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, hdfsDir.getAbsolutePath());
+    conf.set("hadoop.proxyuser." + System.getProperty("user.name") + ".groups", "*");
+    conf.set("hadoop.proxyuser." + System.getProperty("user.name") + ".hosts", "*");
+
+    MiniDFSCluster.Builder builder = new MiniDFSCluster.Builder(conf);
+    hdfsCluster = builder.build();
+    hdfsURI = hdfsCluster.getURI().toString();
+  }
+
+  @AfterClass
+  public static void shutDown() throws Exception {
+    BaseHiveTest.shutDown();
+    hdfsCluster.shutdown();
+    hdfsCluster = null;
+  }
+
+  @Override
+  protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
+    super.setupProperties(properties, baseDir);
+    properties.put("webhdfs.url", hdfsURI);
+    properties.put("webhdfs.username", System.getProperty("user.name"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/ServiceTestUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/ServiceTestUtils.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/ServiceTestUtils.java
new file mode 100644
index 0000000..ac913a9
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/ServiceTestUtils.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.hive;
+
+import org.junit.Assert;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import java.net.URI;
+
+import static org.easymock.EasyMock.*;
+
+public class ServiceTestUtils {
+  public static void assertHTTPResponseOK(Response response) {
+    Assert.assertEquals(200, response.getStatus());
+  }
+
+  public static void assertHTTPResponseCreated(Response response) {
+    Assert.assertEquals(201, response.getStatus());
+  }
+
+  public static void assertHTTPResponseNoContent(Response response) {
+    Assert.assertEquals(204, response.getStatus());
+  }
+
+  public static void expectLocationHeaderInResponse(HttpServletResponse resp_obj) {
+    resp_obj.setHeader(eq("Location"), anyString());
+  }
+
+  public static UriInfo getDefaultUriInfo() {
+    UriInfo uriInfo = createNiceMock(UriInfo.class);
+    URI uri = UriBuilder.fromUri("http://host/a/b").build();
+    expect(uriInfo.getAbsolutePath()).andReturn(uri);
+    replay(uriInfo);
+    return uriInfo;
+  }
+
+  public static HttpServletResponse getResponseWithLocation() {
+    HttpServletResponse resp_obj = createNiceMock(HttpServletResponse.class);
+    expectLocationHeaderInResponse(resp_obj);
+    replay(resp_obj);
+    return resp_obj;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobControllerTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobControllerTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobControllerTest.java
new file mode 100644
index 0000000..ceb3677
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobControllerTest.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.hive.backgroundjobs;
+
+import org.apache.ambari.view.hive.BaseHiveTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BackgroundJobControllerTest extends BaseHiveTest {
+
+  private static final long MAX_WAIT_TIME = 2000;
+
+  @Test
+  public void testStartJob() throws Exception {
+    BackgroundJobController backgroundJobController = new BackgroundJobController(context);
+
+    HangingRunnable runnable = new HangingRunnable();
+    backgroundJobController.startJob("key", runnable);
+
+    assertStateIs(backgroundJobController, "key", Thread.State.RUNNABLE);
+
+    runnable.goOn();
+    assertStateIs(backgroundJobController, "key", Thread.State.TERMINATED);
+  }
+
+  @Test
+  public void testInterrupt() throws Exception {
+    BackgroundJobController backgroundJobController = new BackgroundJobController(context);
+
+    HangingRunnable runnable = new HangingRunnable();
+    backgroundJobController.startJob("key", runnable);
+
+    assertStateIs(backgroundJobController, "key", Thread.State.RUNNABLE);
+
+    backgroundJobController.interrupt("key");
+    assertStateIs(backgroundJobController, "key", Thread.State.TERMINATED);
+  }
+
+  private void assertStateIs(BackgroundJobController backgroundJobController, String key, Thread.State state) throws InterruptedException {
+    long start = System.currentTimeMillis();
+    while (backgroundJobController.state(key) != state) {
+      Thread.sleep(100);
+      if (System.currentTimeMillis() - start > MAX_WAIT_TIME)
+        break;
+    }
+    Assert.assertEquals(state, backgroundJobController.state(key));
+  }
+
+  private static class HangingRunnable implements Runnable {
+    private boolean waitMe = true;
+
+    @Override
+    public void run() {
+      while(waitMe && !Thread.interrupted());
+    }
+
+    public void goOn() {
+      this.waitMe = false;
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/files/FileServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/files/FileServiceTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/files/FileServiceTest.java
new file mode 100644
index 0000000..7ce2dd3
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/files/FileServiceTest.java
@@ -0,0 +1,214 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.resources.files;
+
+import org.apache.ambari.view.hive.ServiceTestUtils;
+import org.apache.ambari.view.hive.HDFSTest;
+import org.apache.ambari.view.hive.utils.*;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.Path;
+import org.json.simple.JSONObject;
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+public class FileServiceTest extends HDFSTest {
+  private final static int PAGINATOR_PAGE_SIZE = 4;  //4 bytes
+  private FileService fileService;
+
+  @Rule public ExpectedException thrown = ExpectedException.none();
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    fileService = getService(FileService.class, handler, context);
+    FilePaginator.setPageSize(PAGINATOR_PAGE_SIZE);
+  }
+
+  @BeforeClass
+  public static void startUp() throws Exception {
+    HDFSTest.startUp(); // super
+  }
+
+  @AfterClass
+  public static void shutDown() throws Exception {
+    HDFSTest.shutDown(); // super
+    HdfsApi.dropAllConnections(); //cleanup API connection
+  }
+
+  @Test
+  public void testCreateFile() throws IOException, InterruptedException {
+    Response response = createFile("/tmp/testCreateFile", "testCreateFile content");
+
+    ServiceTestUtils.assertHTTPResponseNoContent(response);
+    assertHDFSFileContains("/tmp/testCreateFile", "testCreateFile content");
+  }
+
+  @Test
+  public void testCreateExistingFileForbidden() throws IOException, InterruptedException {
+    createFile("/tmp/testOverwriteFile", "original content");
+    thrown.expect(ServiceFormattedException.class);
+    createFile("/tmp/testOverwriteFile", "new content");
+  }
+
+  @Test
+  public void testCreateFilePathNotExists() throws IOException, InterruptedException {
+    Response response = createFile("/non/existent/path/Luke", null);
+    ServiceTestUtils.assertHTTPResponseNoContent(response);
+
+    Response response2 = createFile("/tmp/Leia", null);
+    ServiceTestUtils.assertHTTPResponseNoContent(response2);
+
+    thrown.expect(ServiceFormattedException.class);
+    Response response3 = createFile("/tmp/Leia", null); // file already exists
+    Assert.assertEquals(400, response3.getStatus());
+  }
+
+  @Test
+  public void testUpdateFileContent() throws Exception {
+    createFile("/tmp/testUpdateFileContent", "some content");
+
+    FileService.FileResourceRequest updateRequest = new FileService.FileResourceRequest();
+    updateRequest.file = new FileResource();
+    updateRequest.file.setFileContent("new content");
+
+    Response response = fileService.updateFile(updateRequest, "/tmp/testUpdateFileContent");
+
+    ServiceTestUtils.assertHTTPResponseNoContent(response);
+    assertHDFSFileContains("/tmp/testUpdateFileContent", "new content");
+  }
+
+  @Test
+  public void testPagination() throws Exception {
+    createFile("/tmp/testPagination", "1234567890");  // 10 bytes, 3 pages if 1 page is 4 bytes
+
+    Response response = fileService.getFilePage("/tmp/testPagination", 0L);
+    ServiceTestUtils.assertHTTPResponseOK(response);
+
+    JSONObject obj = ((JSONObject) response.getEntity());
+    assertFileJsonResponseSanity(obj);
+
+    FileResource firstPage = (FileResource) obj.get("file");
+    Assert.assertEquals("1234", firstPage.getFileContent());
+    Assert.assertEquals(3, firstPage.getPageCount());
+    Assert.assertEquals(0, firstPage.getPage());
+    Assert.assertTrue(firstPage.isHasNext());
+    Assert.assertEquals("/tmp/testPagination", firstPage.getFilePath());
+
+
+    response = fileService.getFilePage("/tmp/testPagination", 1L);
+    ServiceTestUtils.assertHTTPResponseOK(response);
+
+    FileResource secondPage = (FileResource) ((JSONObject) response.getEntity()).get("file");
+    Assert.assertEquals("5678", secondPage.getFileContent());
+    Assert.assertEquals(1, secondPage.getPage());
+    Assert.assertTrue(secondPage.isHasNext());
+
+
+    response = fileService.getFilePage("/tmp/testPagination", 2L);
+    ServiceTestUtils.assertHTTPResponseOK(response);
+
+    FileResource thirdPage = (FileResource) ((JSONObject) response.getEntity()).get("file");
+    Assert.assertEquals("90", thirdPage.getFileContent());
+    Assert.assertEquals(2, thirdPage.getPage());
+    Assert.assertFalse(thirdPage.isHasNext());
+
+
+    thrown.expect(BadRequestFormattedException.class);
+    fileService.getFilePage("/tmp/testPagination", 3L);
+  }
+
+  @Test
+  public void testZeroLengthFile() throws Exception {
+    createFile("/tmp/testZeroLengthFile", "");
+
+    Response response = fileService.getFilePage("/tmp/testZeroLengthFile", 0L);
+
+    ServiceTestUtils.assertHTTPResponseOK(response);
+    JSONObject obj = ((JSONObject) response.getEntity());
+    assertFileJsonResponseSanity(obj);
+
+    FileResource fileResource = (FileResource) obj.get("file");
+    Assert.assertEquals("", fileResource.getFileContent());
+    Assert.assertEquals(0, fileResource.getPage());
+    Assert.assertFalse(fileResource.isHasNext());
+  }
+
+  @Test
+  public void testFileNotFound() throws IOException, InterruptedException {
+    assertHDFSFileNotExists("/tmp/notExistentFile");
+
+    thrown.expect(NotFoundFormattedException.class);
+    fileService.getFilePage("/tmp/notExistentFile", 2L);
+  }
+
+  @Test
+  public void testDeleteFile() throws IOException, InterruptedException {
+    createFile("/tmp/testDeleteFile", "some content");
+
+    assertHDFSFileExists("/tmp/testDeleteFile");
+
+    Response response = fileService.deleteFile("/tmp/testDeleteFile");
+    ServiceTestUtils.assertHTTPResponseNoContent(response);
+
+    assertHDFSFileNotExists("/tmp/testDeleteFile");
+  }
+
+
+
+  private Response createFile(String filePath, String content) throws IOException, InterruptedException {
+    FileService.FileResourceRequest request = new FileService.FileResourceRequest();
+    request.file = new FileResource();
+    request.file.setFilePath(filePath);
+    request.file.setFileContent(content);
+
+    return fileService.createFile(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+  }
+
+
+  private void assertFileJsonResponseSanity(JSONObject obj) {
+    Assert.assertTrue(obj.containsKey("file"));
+  }
+
+  private void assertHDFSFileContains(String filePath, String expectedContent) throws IOException {
+    FSDataInputStream fileInputStream = hdfsCluster.getFileSystem().open(new Path(filePath));
+    byte[] buffer = new byte[256];
+    int read = fileInputStream.read(buffer);
+
+    byte[] readData = Arrays.copyOfRange(buffer, 0, read);
+    String actualContent = new String(readData, Charset.forName("UTF-8"));
+
+    Assert.assertEquals(expectedContent, actualContent);
+  }
+
+  private void assertHDFSFileExists(String filePath) throws IOException {
+    Assert.assertTrue( hdfsCluster.getFileSystem().exists(new Path(filePath)) );
+  }
+
+  private void assertHDFSFileNotExists(String filePath) throws IOException {
+    Assert.assertFalse(hdfsCluster.getFileSystem().exists(new Path(filePath)) );
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java
new file mode 100644
index 0000000..78b6f1f
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java
@@ -0,0 +1,210 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.jobs;
+
+import org.apache.ambari.view.hive.ServiceTestUtils;
+import org.apache.ambari.view.hive.BaseHiveTest;
+import org.apache.ambari.view.hive.utils.HdfsApiMock;
+import org.apache.ambari.view.hive.client.Connection;
+import org.apache.ambari.view.hive.client.ConnectionPool;
+import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.resources.savedQueries.SavedQuery;
+import org.apache.ambari.view.hive.resources.savedQueries.SavedQueryService;
+import org.apache.ambari.view.hive.utils.BadRequestFormattedException;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+import org.apache.hive.service.cli.thrift.*;
+import org.json.simple.JSONObject;
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+
+public class JobServiceTest extends BaseHiveTest {
+  private SavedQueryService savedQueryService;
+  private JobService jobService;
+  @Rule public ExpectedException thrown = ExpectedException.none();
+
+  @BeforeClass
+  public static void startUp() throws Exception {
+    BaseHiveTest.startUp(); // super
+  }
+
+  @AfterClass
+  public static void shutDown() throws Exception {
+    BaseHiveTest.shutDown(); // super
+    HdfsApi.dropAllConnections(); //cleanup API connection
+  }
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    savedQueryService = getService(SavedQueryService.class, handler, context);
+    jobService = getService(JobService.class, handler, context);
+
+    Connection hiveConnection = configureHiveConnectionMock();
+
+    ConnectionPool.setInstance(context, hiveConnection);
+  }
+
+  @Test
+  public void createJobFromQuery() throws IOException, InterruptedException {
+    setupHdfsApiMock();
+
+    SavedQuery savedQueryForJob = createSavedQuery("Test", null);
+    JobService.JobRequest jobCreationRequest = new JobService.JobRequest();
+    jobCreationRequest.job = new JobImpl();
+    jobCreationRequest.job.setQueryId(savedQueryForJob.getId());
+
+
+    Response response = jobService.create(jobCreationRequest,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+    ServiceTestUtils.assertHTTPResponseCreated(response);
+    JSONObject jobObj = (JSONObject)response.getEntity();
+
+
+    assertResponseJobSanity(jobObj);
+    Assert.assertEquals(getFieldFromJobJSON(jobObj, "queryId"), savedQueryForJob.getId());
+  }
+
+  @Test
+  public void createJobForcedContent() throws IOException, InterruptedException {
+    HdfsApiMock hdfsApiMock = setupHdfsApiMock();
+
+    JobService.JobRequest request = new JobService.JobRequest();
+    request.job = new JobImpl();
+    request.job.setForcedContent("Hello world");
+
+
+    Response response = jobService.create(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+    ServiceTestUtils.assertHTTPResponseCreated(response);
+    JSONObject jobObj = (JSONObject)response.getEntity();
+
+
+    assertResponseJobSanity(jobObj);
+    Assert.assertNull(getFieldFromJobJSON(jobObj, "queryId"));
+    Assert.assertEquals("", getFieldFromJobJSON(jobObj, "forcedContent"));
+    Assert.assertEquals("Hello world", hdfsApiMock.getQueryOutputStream().toString());
+  }
+
+  @Test
+  public void createJobNoSource() throws IOException, InterruptedException {
+    HdfsApi hdfsApi = createNiceMock(HdfsApi.class);
+    expect(hdfsApi.mkdir(anyString())).andReturn(true).anyTimes();
+    HdfsApi.setInstance(context, hdfsApi);
+    replay(hdfsApi);
+
+    JobService.JobRequest request = new JobService.JobRequest();
+    request.job = new JobImpl();
+    request.job.setForcedContent(null);
+    request.job.setQueryId(null);
+
+    thrown.expect(BadRequestFormattedException.class);
+    jobService.create(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+  }
+
+
+
+  private Connection configureHiveConnectionMock() throws HiveClientException {
+    TGetOperationStatusResp statusResp = getOperationStatusResp();
+    TOperationHandle operationHandle = getExecutionOperationHandle();
+
+    Connection connection = createNiceMock(Connection.class);
+    expect(connection.executeAsync(anyString())).andReturn(operationHandle).anyTimes();
+    expect(connection.getLogs(anyObject(TOperationHandle.class))).andReturn("some logs").anyTimes();
+    expect(connection.getOperationStatus(anyObject(TOperationHandle.class))).andReturn(statusResp).anyTimes();
+
+    replay(connection);
+    return connection;
+  }
+
+  private TGetOperationStatusResp getOperationStatusResp() {
+    TStatus status = new TStatus();
+    status.setStatusCode(TStatusCode.SUCCESS_STATUS);
+
+    TGetOperationStatusResp statusResp = new TGetOperationStatusResp();
+    statusResp.setStatus(status);
+
+    return statusResp;
+  }
+
+  private TOperationHandle getExecutionOperationHandle() {
+    THandleIdentifier handleIdentifier = new THandleIdentifier();
+    handleIdentifier.setGuid("some guid".getBytes());
+    handleIdentifier.setSecret("some secret".getBytes());
+
+    TOperationHandle operationHandle = new TOperationHandle();
+    operationHandle.setHasResultSet(true);
+    operationHandle.setModifiedRowCount(0);
+    operationHandle.setOperationType(TOperationType.EXECUTE_STATEMENT);
+    operationHandle.setOperationId(handleIdentifier);
+    return operationHandle;
+  }
+
+  @Override
+  protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
+    super.setupProperties(properties, baseDir);
+    properties.put("scripts.dir", "/tmp/.hiveQueries");
+    properties.put("jobs.dir", "/tmp/.hiveJobs");
+  }
+
+  public static Response doCreateSavedQuery(String title, String path, SavedQueryService service) {
+    SavedQueryService.SavedQueryRequest request = new SavedQueryService.SavedQueryRequest();
+    request.savedQuery = new SavedQuery();
+    request.savedQuery.setTitle(title);
+    request.savedQuery.setQueryFile(path);
+
+    return service.create(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+  }
+
+  private SavedQuery createSavedQuery(String title, String path) {
+    Response response = doCreateSavedQuery(title, path, savedQueryService);
+    JSONObject obj = (JSONObject)response.getEntity();
+    SavedQuery query = ((SavedQuery) obj.get("savedQuery"));
+    return query;
+  }
+
+
+  private Object getFieldFromJobJSON(JSONObject jobObj, String field) {
+    return ((Map) jobObj.get("job")).get(field);
+  }
+
+  private HdfsApiMock setupHdfsApiMock() throws IOException, InterruptedException {
+    HdfsApiMock hdfsApiMock = new HdfsApiMock("select * from Z");
+    HdfsApi hdfsApi = hdfsApiMock.getHdfsApi();
+    HdfsApi.setInstance(context, hdfsApi);
+    replay(hdfsApi);
+    return hdfsApiMock;
+  }
+
+  private void assertResponseJobSanity(JSONObject jobObj) {
+    Assert.assertTrue(jobObj.containsKey("job"));
+    Assert.assertNotNull(((Map) jobObj.get("job")).get("id"));
+    Assert.assertNotNull(((Map) jobObj.get("job")).get("queryFile"));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/LogParserTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/LogParserTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/LogParserTest.java
new file mode 100644
index 0000000..0c060ed
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/LogParserTest.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.hive.resources.jobs;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LogParserTest {
+    @Test
+    public void testParseMRLog() {
+        String log = "INFO : Number of reduce tasks determined at compile time: 1\n" +
+            "INFO : In order to change the average load for a reducer (in bytes):\n" +
+            "INFO : set hive.exec.reducers.bytes.per.reducer=<number>\n" +
+            "INFO : In order to limit the maximum number of reducers:\n" +
+            "INFO : set hive.exec.reducers.max=<number>\n" +
+            "INFO : In order to set a constant number of reducers:\n" +
+            "INFO : set mapreduce.job.reduces=<number>\n" +
+            "WARN : Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.\n" +
+            "INFO : number of splits:1\n" +
+            "INFO : Submitting tokens for job: job_1421248330903_0003\n" +
+            "INFO : The url to track the job: http://dataworker.hortonworks.com:8088/proxy/application_1421248330903_0003/\n" +
+            "INFO : Starting Job = job_1421248330903_0003, Tracking URL = http://dataworker.hortonworks.com:8088/proxy/application_1421248330903_0003/\n" +
+            "INFO : Kill Command = /usr/hdp/current/hadoop-client/bin/hadoop job -kill job_1421248330903_0003\n" +
+            "INFO : Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1\n" +
+            "INFO : 2015-01-21 15:03:55,979 Stage-1 map = 0%, reduce = 0%\n" +
+            "INFO : 2015-01-21 15:04:07,503 Stage-1 map = 100%, reduce = 0%, Cumulative CPU 0.79 sec\n" +
+            "INFO : 2015-01-21 15:04:17,384 Stage-1 map = 100%, reduce = 100%, Cumulative CPU 1.86 sec\n" +
+            "INFO : MapReduce Total cumulative CPU time: 1 seconds 860 msec\n" +
+            "INFO : Ended Job = job_1421248330903_0003";
+
+        LogParser p = LogParser.parseLog(log);
+        Assert.assertEquals(1, p.getJobsList().size());
+        Assert.assertEquals("application_1421248330903_0003",(((LogParser.JobId) (p.getJobsList().toArray())[0])
+                                                            .getIdentifier()));
+    }
+
+    @Test
+    public void testParseTezLog() {
+        String log = "INFO : Tez session hasn't been created yet. Opening session\n" +
+            "INFO :\n" +
+            "\n" +
+            "INFO : Status: Running (Executing on YARN cluster with App id application_1423156117563_0003)\n" +
+            "\n" +
+            "INFO : Map 1: -/- Reducer 2: 0/1\n" +
+            "INFO : Map 1: 0/1 Reducer 2: 0/1\n" +
+            "INFO : Map 1: 0/1 Reducer 2: 0/1\n" +
+            "INFO : Map 1: 0(+1)/1 Reducer 2: 0/1\n" +
+            "INFO : Map 1: 0(+1)/1 Reducer 2: 0/1\n" +
+            "INFO : Map 1: 1/1 Reducer 2: 0(+1)/1\n" +
+            "INFO : Map 1: 1/1 Reducer 2: 1/1 ";
+
+        LogParser p = LogParser.parseLog(log);
+        Assert.assertEquals(1, p.getJobsList().size());
+        Assert.assertEquals("application_1423156117563_0003",(((LogParser.JobId) (p.getJobsList().toArray())[0])
+            .getIdentifier()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/resources/FileResourceServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/resources/FileResourceServiceTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/resources/FileResourceServiceTest.java
new file mode 100644
index 0000000..06d5269
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/resources/FileResourceServiceTest.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.resources;
+
+import org.apache.ambari.view.hive.BaseHiveTest;
+import org.apache.ambari.view.hive.resources.resources.FileResourceItem;
+import org.apache.ambari.view.hive.resources.resources.FileResourceService;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.json.simple.JSONObject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+import static org.easymock.EasyMock.*;
+
+public class FileResourceServiceTest extends BaseHiveTest {
+  @Rule public ExpectedException thrown = ExpectedException.none();
+  private FileResourceService resourceService;
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    resourceService = getService(FileResourceService.class, handler, context);
+  }
+
+  private Response doCreateFileResourceItem() {
+    FileResourceService.ResourceRequest request = new FileResourceService.ResourceRequest();
+    request.fileResource = new FileResourceItem();
+    request.fileResource.setPath("/tmp/file.jar");
+    request.fileResource.setName("TestFileResourceItem");
+
+    UriInfo uriInfo = createNiceMock(UriInfo.class);
+    URI uri = UriBuilder.fromUri("http://host/a/b").build();
+    expect(uriInfo.getAbsolutePath()).andReturn(uri);
+
+    HttpServletResponse resp_obj = createNiceMock(HttpServletResponse.class);
+
+    resp_obj.setHeader(eq("Location"), anyString());
+
+    replay(uriInfo, resp_obj);
+    return resourceService.create(request, resp_obj, uriInfo);
+  }
+
+  @Test
+  public void createFileResourceItem() {
+    Response response = doCreateFileResourceItem();
+    Assert.assertEquals(201, response.getStatus());
+
+    JSONObject obj = (JSONObject)response.getEntity();
+    Assert.assertTrue(obj.containsKey("fileResource"));
+    Assert.assertNotNull(((FileResourceItem) obj.get("fileResource")).getId());
+    Assert.assertFalse(((FileResourceItem) obj.get("fileResource")).getId() == null);
+  }
+
+  @Test
+  public void resourceNotFound() {
+    thrown.expect(NotFoundFormattedException.class);
+    resourceService.getOne("4242");
+  }
+
+  @Test
+  public void updateFileResourceItem() {
+    Response createdFileResourceItem = doCreateFileResourceItem();
+    Integer createdUdfId = ((FileResourceItem) ((JSONObject) createdFileResourceItem.getEntity()).get("fileResource")).getId();
+
+    FileResourceService.ResourceRequest request = new FileResourceService.ResourceRequest();
+    request.fileResource = new FileResourceItem();
+    request.fileResource.setPath("/tmp/updatedFileResourceItem.jar");
+    request.fileResource.setName("TestFileResourceItem2");
+
+    Response response = resourceService.update(request, String.valueOf(createdUdfId));
+    Assert.assertEquals(204, response.getStatus());
+
+    Response response2 = resourceService.getOne(String.valueOf(createdUdfId));
+    Assert.assertEquals(200, response2.getStatus());
+
+    JSONObject obj = ((JSONObject) response2.getEntity());
+    Assert.assertTrue(obj.containsKey("fileResource"));
+    Assert.assertEquals(((FileResourceItem) obj.get("fileResource")).getName(), request.fileResource.getName());
+    Assert.assertEquals(((FileResourceItem) obj.get("fileResource")).getPath(), request.fileResource.getPath());
+  }
+
+  @Test
+  public void deleteFileResourceItem() {
+    Response createdFileResourceItem = doCreateFileResourceItem();
+    Integer createdUdfId = ((FileResourceItem) ((JSONObject) createdFileResourceItem.getEntity()).get("fileResource")).getId();
+
+    Response response = resourceService.delete(String.valueOf(createdUdfId));
+    Assert.assertEquals(204, response.getStatus());
+
+    thrown.expect(NotFoundFormattedException.class);
+    resourceService.getOne(String.valueOf(createdUdfId));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryServiceTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryServiceTest.java
new file mode 100644
index 0000000..d369bb2
--- /dev/null
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/savedQueries/SavedQueryServiceTest.java
@@ -0,0 +1,177 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.resources.savedQueries;
+
+import org.apache.ambari.view.hive.HDFSTest;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+import org.apache.ambari.view.hive.utils.NotFoundFormattedException;
+import org.json.simple.JSONObject;
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.io.File;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+
+public class SavedQueryServiceTest extends HDFSTest {
+  //TODO: run without HDFS cluster
+  private SavedQueryService savedQueryService;
+  @Rule public ExpectedException thrown = ExpectedException.none();
+
+  @BeforeClass
+  public static void startUp() throws Exception {
+      HDFSTest.startUp(); // super
+  }
+
+  @AfterClass
+  public static void shutDown() throws Exception {
+    HDFSTest.shutDown(); // super
+    HdfsApi.dropAllConnections(); //cleanup API connection
+  }
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    savedQueryService = getService(SavedQueryService.class, handler, context);
+    SavedQueryResourceManager.getViewSingletonObjects().clear();
+  }
+
+  @Override
+  protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
+    super.setupProperties(properties, baseDir);
+    properties.put("scripts.dir", "/tmp/.hiveQueries");
+  }
+
+  private Response doCreateSavedQuery() {
+      return doCreateSavedQuery("Luke", "/tmp/luke.hql", savedQueryService);
+  }
+
+  public static Response doCreateSavedQuery(String title, String path, SavedQueryService service) {
+    SavedQueryService.SavedQueryRequest request = new SavedQueryService.SavedQueryRequest();
+    request.savedQuery = new SavedQuery();
+    request.savedQuery.setTitle(title);
+    request.savedQuery.setQueryFile(path);
+
+    UriInfo uriInfo = createNiceMock(UriInfo.class);
+    URI uri = UriBuilder.fromUri("http://host/a/b").build();
+    expect(uriInfo.getAbsolutePath()).andReturn(uri);
+
+    HttpServletResponse resp_obj = createNiceMock(HttpServletResponse.class);
+
+    resp_obj.setHeader(eq("Location"), anyString());
+
+    replay(uriInfo, resp_obj);
+    return service.create(request, resp_obj, uriInfo);
+  }
+
+  private Response doCreateSavedQuery(String title, String path) {
+      return doCreateSavedQuery(title, path, savedQueryService);
+  }
+
+  @Test
+  public void createSavedQuery() {
+    Response response = doCreateSavedQuery();
+    Assert.assertEquals(201, response.getStatus());
+
+    JSONObject obj = (JSONObject)response.getEntity();
+    Assert.assertTrue(obj.containsKey("savedQuery"));
+    Assert.assertNotNull(((SavedQuery) obj.get("savedQuery")).getId());
+    Assert.assertTrue(((SavedQuery) obj.get("savedQuery")).getId() != null);
+  }
+
+  @Test
+  public void createSavedQueryAutoCreate() {
+    Response response = doCreateSavedQuery("Test", null);
+    Assert.assertEquals(201, response.getStatus());
+
+    JSONObject obj = (JSONObject)response.getEntity();
+    Assert.assertTrue(obj.containsKey("savedQuery"));
+    Assert.assertNotNull(((SavedQuery) obj.get("savedQuery")).getId());
+    Assert.assertFalse(((SavedQuery) obj.get("savedQuery")).getId() == null);
+    Assert.assertFalse(((SavedQuery) obj.get("savedQuery")).getQueryFile().isEmpty());
+  }
+
+  @Test
+  public void notFound() {
+    thrown.expect(NotFoundFormattedException.class);
+    savedQueryService.getOne("4242");
+  }
+
+  @Test
+  public void update() {
+    Response created = doCreateSavedQuery();
+    Integer createdId = ((SavedQuery) ((JSONObject) created.getEntity()).get("savedQuery")).getId();
+
+    SavedQueryService.SavedQueryRequest request = new SavedQueryService.SavedQueryRequest();
+    request.savedQuery = new SavedQuery();
+    request.savedQuery.setTitle("Updated Query");
+
+    Response response = savedQueryService.update(request, String.valueOf(createdId));
+    Assert.assertEquals(204, response.getStatus());
+
+    Response response2 = savedQueryService.getOne(String.valueOf(createdId));
+    Assert.assertEquals(200, response2.getStatus());
+
+    JSONObject obj = ((JSONObject) response2.getEntity());
+    Assert.assertTrue(obj.containsKey("savedQuery"));
+    Assert.assertEquals(((SavedQuery) obj.get("savedQuery")).getTitle(), request.savedQuery.getTitle());
+  }
+
+  @Test
+  public void delete() {
+    Response created = doCreateSavedQuery();
+    Integer createdId = ((SavedQuery) ((JSONObject) created.getEntity()).get("savedQuery")).getId();
+
+    Response response = savedQueryService.delete(String.valueOf(createdId));
+    Assert.assertEquals(204, response.getStatus());
+
+    thrown.expect(NotFoundFormattedException.class);
+    savedQueryService.getOne(String.valueOf(createdId));
+  }
+
+  @Test
+  public void list() {
+    doCreateSavedQuery("Title 1", "/path/to/file.hql");
+    doCreateSavedQuery("Title 2", "/path/to/file.hql");
+
+    Response response = savedQueryService.getList();
+    Assert.assertEquals(200, response.getStatus());
+
+    JSONObject obj = (JSONObject) response.getEntity();
+    Assert.assertTrue(obj.containsKey("savedQueries"));
+    List<SavedQuery> items = (List<SavedQuery>) obj.get("savedQueries");
+    boolean containsTitle = false;
+    for(SavedQuery item : items)
+        containsTitle = containsTitle || item.getTitle().compareTo("Title 1") == 0;
+    Assert.assertTrue(containsTitle);
+
+    containsTitle = false;
+    for(SavedQuery item : items)
+        containsTitle = containsTitle || item.getTitle().compareTo("Title 2") == 0;
+    Assert.assertTrue(containsTitle);
+  }
+}


[04/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
new file mode 100644
index 0000000..315dbbc
--- /dev/null
+++ b/contrib/views/hive/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.append();
+});
+
+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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
new file mode 100644
index 0000000..e8004cc
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
@@ -0,0 +1,130 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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()
+  });
+
+  Ember.run(function() {
+    component.set('dateRange', dateRange);
+  });
+
+  var $component = this.append();
+
+  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.append();
+  $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.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
new file mode 100644
index 0000000..65a50d1
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('expander-widget', 'ExpanderWidgetComponent', {
+});
+
+test('should set the heading when provided.', function () {
+  expect(2);
+
+  var component = this.subject();
+  var $component = this.append();
+  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.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
new file mode 100644
index 0000000..3ef5cf9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('extended-input', 'ExtendedInputComponent');
+
+test('Component has dynamicValue and dynamicContext', function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
+  });
+
+  var $component = this.append();
+
+  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.append();
+
+  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.append();
+
+  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.append();
+
+  Ember.run(function() {
+    component.sendValueChanged();
+
+    equal(component.get('value'), undefined, "Value is not set");
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
new file mode 100644
index 0000000..4ce4ac3
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('no-bubbling', 'NoBubblingWidgetComponent', {
+});
+
+
+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.append();
+
+  $component.trigger('click');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
new file mode 100644
index 0000000..dc95cf7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 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(3);
+
+  var numberRange = Ember.Object.create({
+    max: 1,
+    min: 0
+  });
+
+  var component = this.subject({ numberRange: numberRange });
+  var $component = this.append();
+
+  ok(component.get('slider'), 'Slider is set');
+
+  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.append();
+
+  Ember.run(function() {
+    component.get('slider').slider('value', 1);
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
new file mode 100644
index 0000000..dd6ddd9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('popover-widget', 'PopoverWidgetComponent');
+
+test('Component initializes correctly', function () {
+  expect(2);
+
+  var component = this.subject({
+    template: Ember.Handlebars.compile("test")
+  });
+  var $component = this.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
new file mode 100644
index 0000000..169dc7f
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('progress-widget', 'ProgressWidgetComponent');
+
+test('Setting progress attributes', function () {
+  expect(3);
+
+  var component = this.subject({
+    stages: [
+      Ember.Object.create({ className: 'progress-bar-success', name: 'Execution', value: 10 }),
+      Ember.Object.create({ className: 'progress-bar-danger', name: 'Queued', value: 30 }),
+      Ember.Object.create({ className: 'progress-bar-warning', name: 'Compile', value: 30 })
+    ],
+    formattedStages: Ember.ArrayProxy.create({ content: [] })
+  });
+
+  var $component = this.append();
+
+  Ember.run(function() {
+    component.formatStages();
+
+    equal(component.get('stages').get('firstObject').get('className'), 'progress-bar-success', 'ClassName was set correctly');
+    equal(component.get('stages').get('firstObject').get('name'), 'Execution', 'Name was set correctly');
+    equal(component.get('stages').get('firstObject').get('value'), 10, 'Value was set correctly');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
new file mode 100644
index 0000000..0656ee1
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('query-editor', 'QueryEditorComponent');
+
+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.append();
+
+  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.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
new file mode 100644
index 0000000..9187d00
--- /dev/null
+++ b/contrib/views/hive/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.append();
+
+  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.append();
+
+  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.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
new file mode 100644
index 0000000..f3a1c5f
--- /dev/null
+++ b/contrib/views/hive/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.append();
+
+  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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
new file mode 100644
index 0000000..3f2312b
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
@@ -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.
+ */
+
+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'
+  });
+  var $component = this.append();
+
+  equal(component.get('content.length'), items.length, 'Items are set');
+  equal(component.get('selection'), items[0], 'First object is set as default value');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/columns.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/columns.js
new file mode 100644
index 0000000..f99a5e4
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/columns.js
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:columns', 'ColumnsController', {
+  needs: ['adapter:database']
+});
+
+test('controller is initialized properly.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  ok(controller.get('baseUrl'), 'baseUrl was set to a truthy value.');
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
new file mode 100644
index 0000000..6bcc733
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
@@ -0,0 +1,214 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:databases', 'DatabasesController', {
+  needs: ['component:select-widget',
+          'component:expander-widget',
+          'adapter:database',
+          'controller:tables',
+          'controller:columns',
+          'controller:open-queries'  ]
+});
+
+test('controller is initialized properly.', function () {
+  expect(6);
+
+  var controller = this.subject();
+
+  ok(controller.get('baseUrl'), 'baseUrl was set to a truthy value.');
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [1, 2, 3]
+  });
+
+  controller.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 controller = this.subject();
+
+  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 controller = this.subject();
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [1, 2, 3],
+    visibleTables: [1]
+  });
+
+  controller.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 controller = this.subject();
+
+  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.');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js
new file mode 100644
index 0000000..c43cfda
--- /dev/null
+++ b/contrib/views/hive/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: ['controller:job', 'controller:loaded-files']
+});
+
+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({
+      dateSubmitted: min
+    }),
+    Ember.Object.create({
+      dateSubmitted: 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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
new file mode 100644
index 0000000..291cc7e
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
@@ -0,0 +1,179 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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:index', 'IndexController', {
+  needs: ['controller:databases', 'controller:open-queries', 'controller:insert-udfs',
+          'controller:udfs', 'controller:loaded-files',
+          'controller:index/history-query/logs',
+          'controller:index/history-query/results',
+          'controller:index/history-query/explain',
+          'controller:settings',
+          'adapter:database', 'controller:tables', 'controller:columns']
+});
+
+test('when initialized, controller sets the queryProcessTabs.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  ok(controller.get('queryProcessTabs', 'queryProcessTabs is initialized.'));
+});
+
+test('databasesChanged sets null the selectedTables property of open-queries if databases controller has not set its selectedDatabase.tables property', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  equal(controller.get('databases.selectedTables'), null, 'databases controller property selectedDatabase.tables not set. open-queries selectedTables returns null');
+});
+
+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(3);
+
+  var controller = this.subject();
+
+  var query = "select $what from $where";
+
+  Ember.run(function() {
+    controller.set('openQueries.currentQuery', {
+        'fileContent': 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');
+});
+
+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');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js
new file mode 100644
index 0000000..84803d4
--- /dev/null
+++ b/contrib/views/hive/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:udf', 'controller:udfs', 'controller:file-resources']
+});
+
+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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/job-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/job-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/job-test.js
new file mode 100644
index 0000000..1c76352
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/job-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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:job', 'JobController', {
+  needs: ['controller:history', 'controller:loaded-files']
+});
+
+test('Statuses are computed correctly', function () {
+  expect(5);
+
+  var component = this.subject();
+
+  Ember.run(function() {
+    component.set('content', Ember.Object.create());
+    component.set('content.status', constants.statuses.running);
+  });
+
+  ok(component.get('canStop'), 'Status is running canStop returns true');
+
+  Ember.run(function() {
+    component.set('content.status', constants.statuses.initialized);
+  });
+
+  ok(component.get('canStop'), 'Status is initialized canStop returns true');
+
+  Ember.run(function() {
+    component.set('content.status', constants.statuses.pending);
+  });
+
+  ok(component.get('canStop'), 'Status is pending canStop returns true');
+
+  Ember.run(function() {
+    component.set('content.status', constants.statuses.canceled);
+  });
+
+  ok(!component.get('canStop'), 'Status is canceled canStop returns false');
+
+  Ember.run(function() {
+    component.set('content.status', constants.statuses.unknown);
+  });
+
+  ok(!component.get('canStop'), 'Status is unknown canStop returns false');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js
new file mode 100644
index 0000000..b1c581a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:open-queries', 'OpenQueriesController', {
+  needs: [ 'controller:databases',
+           'controller:loaded-files',
+           'controller:index/history-query/results',
+           'controller:index/history-query/explain',
+           'controller:index',
+           'controller:columns',
+           'controller:settings'
+         ]
+});
+
+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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js
new file mode 100644
index 0000000..0ed7dd7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/queries-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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:queries', 'QueriesController', {
+  needs: [ 'controller:history' ]
+});
+
+test('controller is initialized', function() {
+  expect(1);
+
+  var component = this.subject();
+
+  equal(component.get('columns.length'), 4, 'Columns are initialized correctly');
+});
+
+test('Should hide new queries', function() {
+  expect(1);
+
+  var queries = [
+    { isNew: true },
+    { isNew: false}
+  ];
+
+  var controller = this.subject({
+    queries: queries
+  });
+
+  equal(controller.get('model.length'), 1, 'Hide new queries from the list');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tables.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tables.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tables.js
new file mode 100644
index 0000000..5e0f4b9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tables.js
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:tables', 'TablesController', {
+  needs: ['adapter:database']
+});
+
+test('controller is initialized properly.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  ok(controller.get('baseUrl'), 'baseUrl was set to a truthy value.');
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js
new file mode 100644
index 0000000..c7ba9e4
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:udf', 'UdfController', {
+  needs: [ 'controller:udfs', 'controller:file-resources' ]
+});
+
+test('controller is initialized', function() {
+  expect(2);
+
+  var model = Ember.Object.create({
+    id: 1,
+    name: 'udfmodel',
+    classname: 'cls',
+    isNew: true,
+    fileResource: 'fileresource'
+  });
+
+  var component = this.subject({ model: model});
+
+  ok(component.get('isEditing'), 'Model is new, isEditing is set to true');
+  equal(component.get('fileBackup'), model.get('fileResource'), 'fileBackup is set to model.fileResource');
+});
+
+test('addFileResource', function() {
+  expect(3);
+
+  var model = Ember.Object.create({
+    id: 1,
+    name: 'udfmodel',
+    classname: 'cls',
+    isNew: true,
+    fileResource: null
+  });
+
+  var store = {
+    createRecord: function() {
+      return 'newfileresource';
+    }
+  };
+
+  var component = this.subject({model: model, store: store });
+
+  equal(component.get('model.fileResource'), null, 'fileResource is set to null');
+
+  Ember.run(function () {
+    component.send('addFileResource');
+  });
+
+  ok(component.get('isEditingResource'), 'isEditingResource is set to true');
+  equal(component.get('model.fileResource'), store.createRecord(), 'New file resource is set on the model');
+});
+
+test('editFileResource', function() {
+  expect(3);
+
+  var model = Ember.Object.create({
+    id: 1,
+    name: 'udfmodel',
+    classname: 'cls',
+    isNew: true,
+    fileResource: null
+  });
+
+  var file = 'fileresource';
+  var component = this.subject({model: model });
+
+  equal(component.get('model.fileResource'), null, 'fileResource is set to null');
+
+  Ember.run(function () {
+    component.send('editFileResource', file);
+  });
+
+  ok(component.get('isEditingResource'), 'isEditingResource is set to true');
+  equal(component.get('model.fileResource'), file, 'New file resource is set on the model');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js
new file mode 100644
index 0000000..4160585
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:udfs', 'UdfsController', {
+  needs: [ ]
+});
+
+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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/vendor/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/vendor/.gitkeep b/contrib/views/hive/src/main/resources/ui/hive-web/vendor/.gitkeep
new file mode 100644
index 0000000..e69de29


[06/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
new file mode 100644
index 0000000..8def09e
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.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';
+
+export default Ember.Route.extend({
+  setupController: function() {
+    var self = this;
+
+    this.controllerFor(constants.namingConventions.databases).set('model', this.store.find(constants.namingConventions.database));
+
+    this.store.find(constants.namingConventions.udf).then(function (udfs) {
+      self.controllerFor(constants.namingConventions.udfs).set('udfs', udfs);
+    });
+  },
+
+  actions: {
+    openModal: function(modalTemplate, options) {
+      this.controllerFor(modalTemplate).setProperties({
+        heading: options.heading,
+        text: options.text,
+        defer: options.defer
+      });
+
+      return this.render(modalTemplate, {
+        into: 'application',
+        outlet: 'modal'
+      });
+    },
+
+    closeModal: function () {
+      return this.disconnectOutlet({
+        outlet: 'modal',
+        parentView: 'application'
+      });
+    },
+
+    addAlert: function (type, message, title) {
+      this.controllerFor(constants.namingConventions.alerts).pushObject({
+        type: type,
+        title: title,
+        content: message
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/history.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/history.js
new file mode 100644
index 0000000..7f73f8f
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/history.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';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  model: function () {
+    return this.store.find(constants.namingConventions.job);
+  },
+
+  setupController: function (controller, model) {
+    controller.set('history', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js
new file mode 100644
index 0000000..be5d1f9
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/index.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';
+import constants from 'hive/utils/constants';
+
+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');
+    }
+
+    if (subroute) {
+      this.transitionTo(subroute, model);
+    } else {
+      this.transitionTo(constants.namingConventions.subroutes.jobLogs, model);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/index.js
new file mode 100644
index 0000000..f2be946
--- /dev/null
+++ b/contrib/views/hive/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) {
+      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.routes.index).send('addQuery');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/saved-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/saved-query.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/saved-query.js
new file mode 100644
index 0000000..e64c522
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/index/saved-query.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';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/loading.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/loading.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/loading.js
new file mode 100644
index 0000000..8719170
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/queries.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/queries.js
new file mode 100644
index 0000000..a10bbd7
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/queries.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';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  model: function () {
+    return this.store.find(constants.namingConventions.savedQuery);
+  },
+
+  setupController: function (controller, model) {
+    controller.set('queries', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/udfs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/udfs.js
new file mode 100644
index 0000000..466f632
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/routes/udfs.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';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function () {
+    var self = this;
+
+    this.store.find(constants.namingConventions.fileResource).then(function (fileResources) {
+      self.controllerFor(constants.namingConventions.fileResources).set('model', fileResources);
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/database.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/database.js
new file mode 100644
index 0000000..fed6d14
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/file.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/serializers/file.js
new file mode 100644
index 0000000..416db0c
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
new file mode 100644
index 0000000..6a1d35c
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/app.scss
@@ -0,0 +1,327 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 'dropdown-submenu';
+
+$panel-background: #f5f5f5;
+$placeholder-color: #aaa;
+
+@-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;
+}
+#content {
+  padding: 20px 0;
+}
+
+#alerts-container {
+  position: absolute;
+  left: 15px;
+  right: 15px;
+  z-index: 1100;
+}
+
+aside  hr {
+  margin: 10px 0;
+}
+
+.halfed {
+  width: 50%;
+}
+
+.no-padding {
+  padding: 0;
+}
+
+.no-margin {
+  margin: 0;
+}
+
+.toolbox {
+  margin-top: 15px;
+
+  insert-udfs {
+    display: inline-block;
+  }
+}
+
+.form-control::-moz-placeholder {
+  color: $placeholder-color;
+}
+
+.form-control:-ms-input-placeholder {
+  color: $placeholder-color;
+}
+
+.form-control::-webkit-input-placeholder {
+  color: $placeholder-color;
+}
+
+.secondary-row {
+  background: $panel-background;
+}
+
+.btn-group {
+  .dropdown-menu {
+    right: 0;
+    left: auto;
+  }
+}
+
+.CodeMirror {
+  border: 0 1px solid #ddd;
+}
+
+.grip {
+  height: 20px;
+  border: 0 1px 1px solid #ddd;
+  background-color: $panel-background;
+  color: #bbb;
+  text-align: center;
+  font-size: inherit;
+}
+
+.slider {
+  min-width: 200px;
+}
+
+.slider-labels {
+  font-size: 10px;
+}
+
+.modal-backdrop {
+  background-color: white;
+}
+
+.Unknown {
+  color: gray;
+}
+
+.Running, .Pending, .Initialized, .fa-edit {
+  color: orange;
+}
+
+.Finished {
+  color: green;
+}
+
+.Canceled, .Error {
+  color: red;
+}
+
+dropdown .fa-remove {
+  color: red;
+}
+
+.Closed {
+  color: blue;
+}
+
+.query-container {
+  position: relative;
+  padding-right: 0;
+}
+
+.alert {
+  margin-bottom: 5px;
+  padding-bottom: 10px;
+  padding-top: 10px;
+
+  .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;
+}
+
+.spinner {
+  width: 36px;
+  height: 36px;
+  background: url("/img/spinner.gif");
+  background-repeat: no-repeat;
+  margin: 0px auto;
+
+  &.small {
+    background-size: 20px;
+    width: 20px;
+    height: 20px;
+  }
+}
+
+.databases {
+  max-height: 500px;
+  overflow-y: auto;
+
+  .tables {
+    padding-left: 10px;
+
+    .columns {
+      padding-left: 10px;
+    }
+  }
+}
+
+.selectize-control.plugin-remove_button [data-value] {
+  padding-right: 0 !important;
+}
+
+.popover-right {
+  z-index: 92;
+  float: right;
+  position: relative;
+}
+
+.query-editor-panel .panel-body {
+  position: relative;
+}
+.settings-toggle {
+  position: absolute;
+  top: 0;
+  right: 25px;
+  cursor: pointer;
+}
+
+.settings-toggle.active {
+  color: #428bca;
+}
+.settings-container {
+  width: 100%;
+  overflow-y: scroll;
+  height: calc(100% - 41px);
+  top: 41px;
+  left: 0;
+  background-color: #fff;
+  position: absolute;
+  padding: 0 15px;
+  z-index: 1000;
+  border: 1px solid #ddd;
+
+  -webkit-animation-duration: .5s;
+          animation-duration: .5s;
+  -webkit-animation-fill-mode: both;
+          animation-fill-mode: both;
+}
+.settings-container .close-settings {
+  float: right;
+  font-size: 18px;
+  cursor: pointer;
+  line-height: 24px;
+}
+
+.setting {
+  float: left;
+  margin: 0 10px 10px 0;
+}
+
+.setting .remove {
+  line-height: 30px;
+  margin-left: 10px;
+  font-size: 18px;
+  cursor: pointer;
+}
+
+tabs {
+  display: block;
+  position: relative;
+}
+
+tree-view ul li {
+  padding-left: 10px;
+}
+
+.runOnTez {
+  float: right;
+  margin: 0
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
new file mode 100644
index 0000000..8b43bce
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
@@ -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.
+ */
+
+
+.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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.hbs
new file mode 100644
index 0000000..0fbf34a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/alerts.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 id="alerts-container">
+  {{#each alert in this}}
+    {{alert-message-widget message=alert removeMessage="remove" removeLater="removeLater"}}
+  {{/each}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.hbs
new file mode 100644
index 0000000..055a87b
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/application.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.
+}}
+
+{{render 'navbar'}}
+
+<div id="content">
+  {{outlet}}
+
+  {{outlet "modal"}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/.gitkeep b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs
new file mode 100644
index 0000000..7106f0a
--- /dev/null
+++ b/contrib/views/hive/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>{{tb-helper message.title}}</strong>
+
+  {{#if message.isExpanded}}
+    <div class="alert-message">
+      {{message.content}}
+    </div>
+  {{/if}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs
new file mode 100644
index 0000000..f6af59b
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.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.
+}}
+
+<div>
+  <a {{action "toggle"}} {{bind-attr class=":fa iconClass"}}> {{heading}}</a>
+</div>
+{{#if isExpanded}}
+  {{yield}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs
new file mode 100644
index 0000000..72c72c1
--- /dev/null
+++ b/contrib/views/hive/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"
+                        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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs
new file mode 100644
index 0000000..279ec07
--- /dev/null
+++ b/contrib/views/hive/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.from}}</span>
+  <span class="pull-right">{{numberRange.to}}{{numberRange.units}}</span>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs
new file mode 100644
index 0000000..45c4edf
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/panel-widget.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.
+}}
+
+<div class="panel panel-default" {{bind-attr class=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}}
+      <strong>{{heading}}</strong>
+      {{#if isLoading}}
+        <div class="spinner small pull-right"></div>
+      {{/if}}
+    </div>
+  {{/if}}
+  <div class="panel-body">
+    {{yield}}
+  </div>
+</div>
\ No newline at end of file

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs
new file mode 100644
index 0000000..c89a9dd
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/progress-widget.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="progress">
+  {{#each stage in formattedStages}}
+  <div {{bind-attr class="stage.className :progress-bar"}} {{bind-attr style=stage.progress}}>
+      <span class="sr-only">35% Complete (success)</span>
+    </div>
+  {{/each}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
new file mode 100644
index 0000000..e5f313a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
@@ -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.
+}}
+
+<ul class="nav nav-tabs">
+  {{#each tab in tabs}}
+    {{#if tab.visible}}
+      {{#if tab.path}}
+        {{#link-to tab.path tab.id tagName="li"}}
+          <a>
+            {{tab.name}}
+            {{#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}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/typeahead-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/typeahead-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/typeahead-widget.hbs
new file mode 100644
index 0000000..4083ad6
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/typeahead-widget.hbs
@@ -0,0 +1,17 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
new file mode 100644
index 0000000..38f6b66
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
@@ -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.
+}}
+
+{{#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}}
+  <h4>{{t "labels.noTablesMatches"}} "{{tablesSearchTerm}}"</h4>
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
new file mode 100644
index 0000000..5da9760
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
@@ -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.
+}}
+
+<div class="databases">
+  {{#each database in content}}
+    {{#collapsible-widget heading=database.name isExpanded=database.isExpanded iconClass="fa-database" expanded="getTables"}}
+      {{#if database.isExpanded}}
+        <div class="tables">
+          {{#each table in database.visibleTables}}
+            {{#collapsible-widget heading=table.name isExpanded=table.isExpanded toggledParam=database iconClass="fa-th" expanded="getColumns"}}
+              {{#if table.isExpanded}}
+                <div class="columns">
+                  {{#each column in table.visibleColumns}}
+                    <div>
+                      <strong>{{column.name}}</strong>
+                      <span class="pull-right">{{column.type}}</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>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/databases.hbs
new file mode 100644
index 0000000..115bd70
--- /dev/null
+++ b/contrib/views/hive/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"}}
+  {{#if model}}
+
+    {{typeahead-widget
+        content=model
+        optionValuePath="content.id"
+        optionLabelPath="content.name"
+        selection=selectedDatabase
+    }}
+
+    <hr />
+
+    {{#if selectedDatabase}}
+      {{extended-input class="form-control input-sm"
+                       placeholderTranslation="placeholders.search.tables"
+                       valueSearched="searchTables"
+                       value=tableSearchTerm}}
+
+      <hr />
+    {{/if}}
+
+
+    {{#if tableSearchResults.tables}}
+      {{extended-input class="form-control input-sm"
+                       placeholderTranslation="placeholders.search.columns"
+                       valueSearched="searchColumns"
+                       value=columnSearchTerm}}
+
+      <hr />
+    {{/if}}
+
+    {{#tabs-widget tabs=tabs selectedTab=selectedTab}}
+      {{partial selectedTab.view}}
+    {{/tabs-widget}}
+  {{/if}}
+{{/panel-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/history.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/history.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/history.hbs
new file mode 100644
index 0000000..22c2ff3
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/history.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.
+}}
+
+<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>
+    {{#each item in this}}
+      <tr class="main-row" {{action "loadFile"}}>
+        <td>
+        {{#link-to "index.historyQuery" item}}
+          {{item.title}}
+        {{/link-to}}
+        </td>
+        <td {{bind-attr class=item.status}}>{{item.status}}</td>
+        <td>{{date-binding item "dateSubmitted"}}</td>
+        <td>{{item.duration}}</td>
+        <td>
+          <a class="fa fa-expand pull-right"></a>
+        </td>
+      </tr>
+      {{#if controller.expanded}}
+        <tr class="secondary-row">
+          <td {{bind-attr colspan=view.colspan}}>
+            {{code-helper controller.file.fileContent}}
+
+            {{#if controller.canStop}}
+              <button type="button" class="btn btn-danger btn-sm pull-right" {{action "stop"}}>{{t "buttons.stopJob"}}</button>
+            {{/if}}
+          </td>
+        </tr>
+      {{/if}}
+    {{/each}}
+  </tbody>
+</table>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index.hbs
new file mode 100644
index 0000000..622af66
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index.hbs
@@ -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.
+}}
+
+<aside class="col-md-3 col-xs-12 pull-left no-padding">
+  {{render 'databases'}}
+</aside>
+
+<div class="col-md-9 col-xs 12 pull-left query-container">
+
+  {{render 'alerts'}}
+  {{#panel-widget headingTranslation="titles.query.editor" classNames="query-editor-panel"}}
+    {{#popover-widget classNames="fa fa-info-circle popover-right" 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 'open-queries'}}
+
+    <div class="toolbox">
+      <button type="button" class="btn btn-sm btn-success execute-query"
+              {{bind-attr class="canExecute::disabled"}}
+              {{action "executeQuery"}}>
+        {{t "buttons.execute"}}
+      </button>
+      <button type="button" class="btn btn-sm btn-default"
+              {{bind-attr class="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'}}
+
+      <button type="button" class="btn btn-sm btn-primary  pull-right" {{action "addQuery"}}>{{t "buttons.newQuery"}}</button>
+    </div>
+  {{/panel-widget}}
+
+  {{#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 headingTranslation="titles.query.process"
+                    isLoading=model.isRunning
+                    menuItems=downloadMenu
+                    menuHeadingTranslation="titles.download"
+                    classNames="query-process-results-panel"}}
+      {{#tabs-widget tabs=queryProcessTabs selectedTab=selectedQueryProcessTab}}
+        {{outlet}}
+      {{/tabs-widget}}
+    {{/panel-widget}}
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs b/contrib/views/hive/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/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
new file mode 100644
index 0000000..ed6fba6
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
@@ -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.
+}}
+
+{{#if results}}
+  <table class="table table-expandable">
+    <thead>
+      <tr>
+        {{#each column in results.schema}}
+          <th> {{column.name}} </th>
+        {{/each}}
+      </tr>
+    </thead>
+    <tbody>
+      {{#each row in results.rows}}
+        <tr>
+          {{#each item in row}}
+            <td>{{item}}</td>
+          {{/each}}
+        </tr>
+      {{/each}}
+    </tbody>
+  </table>
+
+  <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>
+{{else}}
+  {{error}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs
new file mode 100644
index 0000000..0ea2c99
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/insert-udfs.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="dropdown">
+  <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>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/loading.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/loading.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/loading.hbs
new file mode 100644
index 0000000..c0de275
--- /dev/null
+++ b/contrib/views/hive/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/f5482d89/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/logs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/logs.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/logs.hbs
new file mode 100644
index 0000000..283d929
--- /dev/null
+++ b/contrib/views/hive/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


[12/12] ambari git commit: AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)

Posted by al...@apache.org.
AMBARI-9676. Initial Hive View Submission to Contrib (alexantonenko)


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

Branch: refs/heads/branch-2.0.0
Commit: f5482d89da0481f642dda58e7dae4e0fe76d64bc
Parents: 828d85d
Author: Alex Antonenko <hi...@gmail.com>
Authored: Tue Feb 24 18:28:59 2015 +0200
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Tue Feb 24 18:31:21 2015 +0200

----------------------------------------------------------------------
 contrib/views/hive/pom.xml                      | 306 ++++++++++++
 .../apache/ambari/view/hive/BaseService.java    |  58 +++
 .../apache/ambari/view/hive/HelpService.java    |  72 +++
 .../org/apache/ambari/view/hive/TestBean.java   |  36 ++
 .../backgroundjobs/BackgroundJobController.java |  80 ++++
 .../view/hive/client/ColumnDescription.java     |  30 ++
 .../hive/client/ColumnDescriptionExtended.java  | 103 ++++
 .../hive/client/ColumnDescriptionShort.java     |  72 +++
 .../ambari/view/hive/client/Connection.java     | 401 ++++++++++++++++
 .../ambari/view/hive/client/ConnectionPool.java |  81 ++++
 .../apache/ambari/view/hive/client/Cursor.java  | 233 +++++++++
 .../ambari/view/hive/client/DDLDelegator.java   | 140 ++++++
 .../ambari/view/hive/client/HiveCall.java       |  68 +++
 .../view/hive/client/HiveClientException.java   |  25 +
 .../hive/client/HiveClientRuntimeException.java |  25 +
 .../hive/client/HiveErrorStatusException.java   |  30 ++
 .../ambari/view/hive/client/LogsCursor.java     |  36 ++
 .../org/apache/ambari/view/hive/client/Row.java |  50 ++
 .../apache/ambari/view/hive/client/Utils.java   |  72 +++
 .../view/hive/client/ViewSessionState.java      |  32 ++
 .../view/hive/persistence/DataStoreStorage.java | 186 ++++++++
 .../persistence/InstanceKeyValueStorage.java    | 140 ++++++
 .../view/hive/persistence/KeyValueStorage.java  | 162 +++++++
 .../hive/persistence/LocalKeyValueStorage.java  |  78 +++
 .../persistence/PersistentConfiguration.java    |  52 ++
 .../ambari/view/hive/persistence/Storage.java   |  86 ++++
 .../utils/ContextConfigurationAdapter.java      | 260 ++++++++++
 .../persistence/utils/FilteringStrategy.java    |  31 ++
 .../view/hive/persistence/utils/Indexed.java    |  36 ++
 .../hive/persistence/utils/ItemNotFound.java    |  25 +
 .../utils/OnlyOwnersFilteringStrategy.java      |  33 ++
 .../view/hive/persistence/utils/Owned.java      |  36 ++
 .../persistence/utils/PersonalResource.java     |  22 +
 .../hive/persistence/utils/StorageUtil.java     |  94 ++++
 .../hive/resources/CRUDResourceManager.java     | 133 ++++++
 .../resources/PersonalCRUDResourceManager.java  | 109 +++++
 .../resources/SharedCRUDResourceManager.java    |  50 ++
 .../resources/browser/HiveBrowserService.java   | 263 ++++++++++
 .../view/hive/resources/files/FileResource.java |  70 +++
 .../view/hive/resources/files/FileService.java  | 185 ++++++++
 .../resources/jobs/ConnectionController.java    |  62 +++
 .../hive/resources/jobs/FileResourceShort.java  |  55 +++
 .../ambari/view/hive/resources/jobs/Job.java    |  90 ++++
 .../view/hive/resources/jobs/JobController.java |  46 ++
 .../resources/jobs/JobControllerFactory.java    |  43 ++
 .../hive/resources/jobs/JobControllerImpl.java  | 326 +++++++++++++
 .../view/hive/resources/jobs/JobImpl.java       | 203 ++++++++
 .../hive/resources/jobs/JobResourceManager.java | 107 +++++
 .../resources/jobs/JobResourceProvider.java     | 108 +++++
 .../view/hive/resources/jobs/JobService.java    | 355 ++++++++++++++
 .../view/hive/resources/jobs/LogParser.java     | 113 +++++
 .../jobs/ModifyNotificationDelegate.java        |  23 +
 .../ModifyNotificationInvocationHandler.java    |  40 ++
 .../jobs/NoOperationStatusSetException.java     |  26 +
 .../jobs/OperationHandleController.java         | 113 +++++
 .../jobs/OperationHandleControllerFactory.java  |  52 ++
 .../jobs/OperationHandleResourceManager.java    |  85 ++++
 .../jobs/ResultsPaginationController.java       | 180 +++++++
 .../resources/jobs/StoredOperationHandle.java   | 146 ++++++
 .../resources/resources/FileResourceItem.java   |  78 +++
 .../resources/FileResourceResourceManager.java  |  64 +++
 .../resources/FileResourceResourceProvider.java | 107 +++++
 .../resources/FileResourceService.java          | 181 +++++++
 .../hive/resources/savedQueries/SavedQuery.java |  96 ++++
 .../savedQueries/SavedQueryResourceManager.java | 132 ++++++
 .../SavedQueryResourceProvider.java             | 104 ++++
 .../savedQueries/SavedQueryService.java         | 184 +++++++
 .../ambari/view/hive/resources/udfs/UDF.java    |  87 ++++
 .../hive/resources/udfs/UDFResourceManager.java |  64 +++
 .../resources/udfs/UDFResourceProvider.java     | 107 +++++
 .../view/hive/resources/udfs/UDFService.java    | 196 ++++++++
 .../utils/BadRequestFormattedException.java     |  27 ++
 .../ambari/view/hive/utils/FilePaginator.java   | 127 +++++
 .../apache/ambari/view/hive/utils/HdfsApi.java  | 399 ++++++++++++++++
 .../apache/ambari/view/hive/utils/HdfsUtil.java |  87 ++++
 .../MisconfigurationFormattedException.java     |  47 ++
 .../hive/utils/NotFoundFormattedException.java  |  27 ++
 .../hive/utils/ServiceFormattedException.java   |  78 +++
 .../src/main/resources/ui/hive-web/.gitignore   |  35 ++
 .../src/main/resources/ui/hive-web/.jshintrc    |  32 ++
 .../src/main/resources/ui/hive-web/Brocfile.js  |  46 ++
 .../src/main/resources/ui/hive-web/README.md    |  14 +
 .../ui/hive-web/app/adapters/application.js     |  44 ++
 .../ui/hive-web/app/adapters/database.js        |  25 +
 .../resources/ui/hive-web/app/adapters/file.js  |  26 +
 .../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        |  33 ++
 .../app/components/column-filter-widget.js      |  56 +++
 .../app/components/date-range-widget.js         |  62 +++
 .../hive-web/app/components/expander-widget.js  |  30 ++
 .../hive-web/app/components/extended-input.js   |  50 ++
 .../ui/hive-web/app/components/modal-widget.js  |  34 ++
 .../ui/hive-web/app/components/no-bubbling.js   |  31 ++
 .../app/components/number-range-widget.js       |  52 ++
 .../ui/hive-web/app/components/panel-widget.js  |  30 ++
 .../hive-web/app/components/popover-widget.js   |  33 ++
 .../hive-web/app/components/progress-widget.js  |  45 ++
 .../ui/hive-web/app/components/query-editor.js  | 121 +++++
 .../ui/hive-web/app/components/select-widget.js |  66 +++
 .../ui/hive-web/app/components/tabs-widget.js   |  64 +++
 .../ui/hive-web/app/components/tree-view.js     |  23 +
 .../hive-web/app/components/typeahead-widget.js |  44 ++
 .../ui/hive-web/app/controllers/.gitkeep        |   0
 .../ui/hive-web/app/controllers/alerts.js       |  47 ++
 .../ui/hive-web/app/controllers/columns.js      | 104 ++++
 .../ui/hive-web/app/controllers/databases.js    | 354 ++++++++++++++
 .../hive-web/app/controllers/file-resources.js  |  22 +
 .../ui/hive-web/app/controllers/history.js      | 148 ++++++
 .../ui/hive-web/app/controllers/index.js        | 475 +++++++++++++++++++
 .../controllers/index/history-query/explain.js  | 119 +++++
 .../app/controllers/index/history-query/logs.js |  95 ++++
 .../controllers/index/history-query/results.js  | 134 ++++++
 .../ui/hive-web/app/controllers/insert-udfs.js  |  58 +++
 .../ui/hive-web/app/controllers/job.js          |  49 ++
 .../ui/hive-web/app/controllers/loaded-files.js |  65 +++
 .../ui/hive-web/app/controllers/modal-delete.js |  33 ++
 .../ui/hive-web/app/controllers/modal-save.js   |  33 ++
 .../ui/hive-web/app/controllers/open-queries.js | 320 +++++++++++++
 .../ui/hive-web/app/controllers/queries.js      | 107 +++++
 .../ui/hive-web/app/controllers/settings.js     | 150 ++++++
 .../ui/hive-web/app/controllers/tables.js       |  93 ++++
 .../ui/hive-web/app/controllers/udf.js          | 138 ++++++
 .../ui/hive-web/app/controllers/udfs.js         |  69 +++
 .../resources/ui/hive-web/app/helpers/.gitkeep  |   0
 .../ui/hive-web/app/helpers/code-helper.js      |  28 ++
 .../ui/hive-web/app/helpers/date-binding.js     |  27 ++
 .../ui/hive-web/app/helpers/log-helper.js       |  28 ++
 .../ui/hive-web/app/helpers/path-binding.js     |  29 ++
 .../ui/hive-web/app/helpers/tb-helper.js        |  33 ++
 .../main/resources/ui/hive-web/app/index.html   |  38 ++
 .../ui/hive-web/app/initializers/i18n.js        | 160 +++++++
 .../ui/hive-web/app/mixins/filterable.js        | 104 ++++
 .../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     |  32 ++
 .../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    |  47 ++
 .../resources/ui/hive-web/app/routes/.gitkeep   |   0
 .../ui/hive-web/app/routes/application.js       |  62 +++
 .../resources/ui/hive-web/app/routes/history.js |  30 ++
 .../app/routes/index/history-query/explain.js   |  28 ++
 .../app/routes/index/history-query/index.js     |  37 ++
 .../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 |  33 ++
 .../resources/ui/hive-web/app/routes/loading.js |  22 +
 .../resources/ui/hive-web/app/routes/queries.js |  30 ++
 .../resources/ui/hive-web/app/routes/udfs.js    |  30 ++
 .../ui/hive-web/app/serializers/database.js     |  41 ++
 .../ui/hive-web/app/serializers/file.js         |  23 +
 .../resources/ui/hive-web/app/styles/.gitkeep   |   0
 .../resources/ui/hive-web/app/styles/app.scss   | 327 +++++++++++++
 .../hive-web/app/styles/dropdown-submenu.scss   |  66 +++
 .../ui/hive-web/app/templates/.gitkeep          |   0
 .../ui/hive-web/app/templates/alerts.hbs        |  23 +
 .../ui/hive-web/app/templates/application.hbs   |  25 +
 .../hive-web/app/templates/components/.gitkeep  |   0
 .../components/alert-message-widget.hbs         |  28 ++
 .../templates/components/collapsible-widget.hbs |  24 +
 .../components/column-filter-widget.hbs         |  42 ++
 .../templates/components/date-range-widget.hbs  |  22 +
 .../templates/components/expander-widget.hbs    |  31 ++
 .../app/templates/components/modal-widget.hbs   |  35 ++
 .../app/templates/components/no-bubbling.hbs    |  19 +
 .../components/number-range-widget.hbs          |  23 +
 .../app/templates/components/panel-widget.hbs   |  46 ++
 .../app/templates/components/popover-widget.hbs |  19 +
 .../templates/components/progress-widget.hbs    |  25 +
 .../app/templates/components/query-editor.hbs   |  19 +
 .../app/templates/components/select-widget.hbs  |  39 ++
 .../app/templates/components/tabs-widget.hbs    |  40 ++
 .../app/templates/components/tree-view.hbs      |  28 ++
 .../templates/components/typeahead-widget.hbs   |  17 +
 .../app/templates/databases-search-results.hbs  |  48 ++
 .../hive-web/app/templates/databases-tree.hbs   |  48 ++
 .../ui/hive-web/app/templates/databases.hbs     |  54 +++
 .../ui/hive-web/app/templates/history.hbs       |  70 +++
 .../ui/hive-web/app/templates/index.hbs         |  82 ++++
 .../templates/index/history-query/explain.hbs   |  23 +
 .../app/templates/index/history-query/logs.hbs  |  19 +
 .../templates/index/history-query/results.hbs   |  47 ++
 .../ui/hive-web/app/templates/insert-udfs.hbs   |  44 ++
 .../ui/hive-web/app/templates/loading.hbs       |  19 +
 .../ui/hive-web/app/templates/logs.hbs          |  19 +
 .../ui/hive-web/app/templates/modal-delete.hbs  |  21 +
 .../ui/hive-web/app/templates/modal-save.hbs    |  21 +
 .../ui/hive-web/app/templates/navbar.hbs        |  45 ++
 .../ui/hive-web/app/templates/open-queries.hbs  |  23 +
 .../ui/hive-web/app/templates/queries.hbs       |  78 +++
 .../ui/hive-web/app/templates/redirect.hbs      |  19 +
 .../ui/hive-web/app/templates/settings.hbs      |  52 ++
 .../ui/hive-web/app/templates/udfs.hbs          | 112 +++++
 .../ui/hive-web/app/transforms/date.js          |  49 ++
 .../ui/hive-web/app/utils/constants.js          | 122 +++++
 .../ui/hive-web/app/utils/functions.js          |  36 ++
 .../resources/ui/hive-web/app/views/.gitkeep    |   0
 .../resources/ui/hive-web/app/views/history.js  |  25 +
 .../ui/hive-web/app/views/insert-udfs.js        |  23 +
 .../resources/ui/hive-web/app/views/navbar.js   |  38 ++
 .../main/resources/ui/hive-web/big_tables.js    |  54 +++
 .../src/main/resources/ui/hive-web/bower.json   |  27 ++
 .../resources/ui/hive-web/config/environment.js |  65 +++
 .../src/main/resources/ui/hive-web/package.json |  45 ++
 .../src/main/resources/ui/hive-web/testem.json  |  11 +
 .../main/resources/ui/hive-web/tests/.jshintrc  |  74 +++
 .../ui/hive-web/tests/blanket-options.js        |  25 +
 .../ui/hive-web/tests/helpers/api-mock.js       | 242 ++++++++++
 .../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 -> 3289 bytes
 .../main/resources/ui/hive-web/tests/index.html |  64 +++
 .../hive-web/tests/integration/database-test.js | 105 ++++
 .../hive-web/tests/integration/history-test.js  |  95 ++++
 .../tests/integration/query-editor-test.js      | 108 +++++
 .../tests/integration/saved-queries-test.js     | 126 +++++
 .../ui/hive-web/tests/integration/udfs-test.js  |  91 ++++
 .../resources/ui/hive-web/tests/test-helper.js  |  30 ++
 .../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  |  44 ++
 .../components/column-filter-widget-test.js     | 138 ++++++
 .../unit/components/date-range-widget-test.js   | 130 +++++
 .../unit/components/expander-widget-test.js     |  58 +++
 .../unit/components/extended-input-test.js      |  79 +++
 .../tests/unit/components/no-bubbling-test.js   |  43 ++
 .../unit/components/number-range-widget-test.js |  72 +++
 .../unit/components/popover-widget-test.js      |  34 ++
 .../unit/components/progress-widget-test.js     |  45 ++
 .../tests/unit/components/query-editor-test.js  |  50 ++
 .../tests/unit/components/select-widget-test.js | 158 ++++++
 .../tests/unit/components/tabs-wiget-test.js    | 117 +++++
 .../unit/components/typeahead-widget-test.js    |  45 ++
 .../hive-web/tests/unit/controllers/columns.js  |  32 ++
 .../tests/unit/controllers/databases-test.js    | 214 +++++++++
 .../tests/unit/controllers/history-test.js      | 117 +++++
 .../tests/unit/controllers/index-test.js        | 179 +++++++
 .../tests/unit/controllers/insert-udfs-test.js  |  68 +++
 .../hive-web/tests/unit/controllers/job-test.js |  62 +++
 .../tests/unit/controllers/open-queries-test.js | 103 ++++
 .../tests/unit/controllers/queries-test.js      |  47 ++
 .../hive-web/tests/unit/controllers/tables.js   |  32 ++
 .../hive-web/tests/unit/controllers/udf-test.js |  94 ++++
 .../tests/unit/controllers/udfs-test.js         |  62 +++
 .../tests/unit/helpers/path-binding-test.js     |  35 ++
 .../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 ++++++++
 contrib/views/hive/src/main/resources/view.xml  | 160 +++++++
 .../apache/ambari/view/hive/BaseHiveTest.java   | 103 ++++
 .../org/apache/ambari/view/hive/HDFSTest.java   |  64 +++
 .../ambari/view/hive/ServiceTestUtils.java      |  63 +++
 .../BackgroundJobControllerTest.java            |  77 +++
 .../hive/resources/files/FileServiceTest.java   | 214 +++++++++
 .../hive/resources/jobs/JobServiceTest.java     | 210 ++++++++
 .../view/hive/resources/jobs/LogParserTest.java |  73 +++
 .../resources/FileResourceServiceTest.java      | 119 +++++
 .../savedQueries/SavedQueryServiceTest.java     | 177 +++++++
 .../hive/resources/udfs/UDFServiceTest.java     | 119 +++++
 .../ambari/view/hive/utils/HdfsApiMock.java     |  84 ++++
 .../utils/SeekableByteArrayInputStream.java     |  71 +++
 contrib/views/pom.xml                           |   1 +
 pom.xml                                         |   1 +
 274 files changed, 21147 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive/pom.xml b/contrib/views/hive/pom.xml
new file mode 100644
index 0000000..0ed6af4
--- /dev/null
+++ b/contrib/views/hive/pom.xml
@@ -0,0 +1,306 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.ambari.contrib.views</groupId>
+  <artifactId>hive</artifactId>
+  <version>0.1.0-SNAPSHOT</version>
+  <name>Hive</name>
+
+  <parent>
+    <groupId>org.apache.ambari.contrib.views</groupId>
+    <artifactId>ambari-contrib-views</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <dependencies>
+    <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>
+    </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.apache.hadoop</groupId>
+      <artifactId>hadoop-hdfs</artifactId>
+      <version>${hadoop-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+      <version>${hadoop-version}</version>
+    </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-service</artifactId>
+      <version>${hive-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-common</artifactId>
+      <version>${hive-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-shims</artifactId>
+      <version>${hive-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-metastore</artifactId>
+      <version>${hive-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-exec</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>org.apache.hadoop</groupId>
+      <artifactId>hadoop-minicluster</artifactId>
+      <version>${hadoop-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <hadoop-version>2.6.0</hadoop-version>
+    <ambari.dir>${project.parent.parent.parent.basedir}</ambari.dir>
+    <hive-version>1.0.0</hive-version>
+    <ambari.version>1.3.0-SNAPSHOT</ambari.version>
+  </properties>
+  <build>
+    <plugins>
+
+      <!-- Building frontend -->
+      <plugin>
+        <groupId>com.github.eirslett</groupId>
+        <artifactId>frontend-maven-plugin</artifactId>
+        <version>0.0.14</version>
+        <configuration>
+          <nodeVersion>v0.10.26</nodeVersion>
+          <npmVersion>1.4.3</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.6</source>
+          <target>1.6</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>
+        </includes>
+      </resource>
+      <resource>
+        <directory>src/main/resources/ui/hive-web/dist</directory>
+        <filtering>false</filtering>
+      </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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/BaseService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/BaseService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/BaseService.java
new file mode 100644
index 0000000..e28193d
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/BaseService.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.persistence.Storage;
+import org.apache.ambari.view.hive.persistence.utils.StorageUtil;
+import org.apache.ambari.view.hive.utils.HdfsApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Parent service
+ */
+public class BaseService {
+  @Inject
+  protected ViewContext context;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(BaseService.class);
+
+  private Storage storage;
+  protected Storage getStorage() {
+    if (storage == null) {
+      storage = StorageUtil.getInstance(context).getStorage();
+    }
+    return storage;
+  }
+
+  private HdfsApi hdfsApi = null;
+  protected HdfsApi getHdfsApi()  {
+    if (hdfsApi == null)
+      hdfsApi = HdfsApi.getInstance(context);
+    return hdfsApi;
+  }
+
+  public BaseService() {
+//    Thread.currentThread().setContextClassLoader(null);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/HelpService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/HelpService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/HelpService.java
new file mode 100644
index 0000000..f975393
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/HelpService.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive;
+
+import com.google.inject.Inject;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+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();
+  }
+
+  /**
+   * Version
+   * @return version
+   */
+  @GET
+  @Path("/test")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response testStorage(){
+    TestBean test = new TestBean();
+    test.someData = "hello world";
+    getStorage().store(TestBean.class, test);
+    return Response.ok("OK").build();
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobController.java
new file mode 100644
index 0000000..6bc284e
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/backgroundjobs/BackgroundJobController.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescription.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescription.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescription.java
new file mode 100644
index 0000000..d7ea560
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescription.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.hive.client;
+
+public interface ColumnDescription {
+  public abstract String getName();
+  public abstract void setName(String name);
+
+  public abstract String getType();
+  public abstract void setType(String type);
+
+  public abstract int getPosition();
+  public abstract void setPosition(int position);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionExtended.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionExtended.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionExtended.java
new file mode 100644
index 0000000..ab54e61
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionExtended.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.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;
+
+  private ColumnDescriptionExtended(String name, String type, String comment, boolean partitioned,
+                                   boolean sortedBy, boolean clusteredBy, int position) {
+    setName(name);
+    setType(type);
+    setPosition(position);
+    setComment(comment);
+    setPartitioned(partitioned);
+    setSortedBy(sortedBy);
+    setClusteredBy(clusteredBy);
+  }
+
+  public static ColumnDescription createExtendedColumnDescription(String name, String type, String comment,
+                                                                  boolean partitioned, boolean sortedBy, boolean clusteredBy,
+                                                                  int position) {
+    return new ColumnDescriptionExtended(name, type, comment, partitioned, sortedBy, clusteredBy, position);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public int getPosition() {
+    return position;
+  }
+
+  public void setPosition(int position) {
+    this.position = position;
+  }
+
+  public String getComment() {
+    return comment;
+  }
+
+  public void setComment(String comment) {
+    this.comment = comment;
+  }
+
+  public boolean isPartitioned() {
+    return partitioned;
+  }
+
+  public void setPartitioned(boolean partitioned) {
+    this.partitioned = partitioned;
+  }
+
+  public boolean isSortedBy() {
+    return sortedBy;
+  }
+
+  public void setSortedBy(boolean sortedBy) {
+    this.sortedBy = sortedBy;
+  }
+
+  public boolean isClusteredBy() {
+    return clusteredBy;
+  }
+
+  public void setClusteredBy(boolean clusteredBy) {
+    this.clusteredBy = clusteredBy;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionShort.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionShort.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionShort.java
new file mode 100644
index 0000000..a6500aa
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ColumnDescriptionShort.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import java.util.ArrayList;
+
+public class ColumnDescriptionShort extends ArrayList<Object> implements ColumnDescription {
+  public static final int INITIAL_CAPACITY = 3;
+  public static final int NAME_INDEX = 0;
+  public static final int TYPE_INDEX = 1;
+  public static final int POSITION_INDEX = 2;
+
+  private ColumnDescriptionShort(String name, String type, int position) {
+    super(INITIAL_CAPACITY);
+    this.add(null);
+    this.add(null);
+    this.add(null);
+    setName(name);
+    setType(type);
+    setPosition(position);
+  }
+
+  public static ColumnDescription createShortColumnDescription(String name, String type, int position) {
+    return new ColumnDescriptionShort(name, type, position);
+  }
+
+  @Override
+  public String getName() {
+    return (String) this.get(NAME_INDEX);
+  }
+
+  @Override
+  public void setName(String name) {
+    this.set(NAME_INDEX, name);
+  }
+
+  @Override
+  public String getType() {
+    return (String) this.get(TYPE_INDEX);
+  }
+
+  @Override
+  public void setType(String type) {
+    this.set(TYPE_INDEX, type);
+  }
+
+  @Override
+  public int getPosition() {
+    return (Integer) this.get(POSITION_INDEX);
+  }
+
+  @Override
+  public void setPosition(int position) {
+    this.set(POSITION_INDEX, position);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java
new file mode 100644
index 0000000..e713aba
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java
@@ -0,0 +1,401 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.client;
+
+import org.apache.hadoop.hive.shims.ShimLoader;
+import org.apache.hive.service.auth.HiveAuthFactory;
+import org.apache.hive.service.auth.KerberosSaslHelper;
+import org.apache.hive.service.auth.PlainSaslHelper;
+import org.apache.hive.service.auth.SaslQOP;
+import org.apache.hive.service.cli.thrift.*;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Holds session
+ */
+public class Connection {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(Connection.class);
+  private String host;
+  private int port;
+  private Map<String, String> authParams;
+
+  private TCLIService.Client client = null;
+  private TSessionHandle sessHandle = null;
+  private TProtocolVersion protocol = null;
+  private TTransport transport;
+
+  private DDLDelegator ddl;
+
+  public Connection(String host, int port, Map<String, String> authParams) throws HiveClientException {
+    this.host = host;
+    this.port = port;
+    this.authParams = authParams;
+
+    openConnection();
+    ddl = new DDLDelegator(this);
+  }
+
+  public DDLDelegator ddl() {
+    return ddl;
+  }
+
+  public synchronized void openConnection() throws HiveClientException {
+    try {
+      transport = getTransport();
+      transport.open();
+      client = new TCLIService.Client(new TBinaryProtocol(transport));
+    } catch (TTransportException e) {
+      throw new HiveClientException("Could not establish connecton to "
+          + host + ":" + port + ": " + e.toString(), e);
+    }
+    LOG.info("Hive connection opened");
+    openSession();
+  }
+
+  /**
+   * Based on JDBC implementation of HiveConnection.createBinaryTransport
+   * @return transport
+   * @throws HiveClientException
+   */
+  protected TTransport getTransport() throws HiveClientException, TTransportException {
+    TTransport transport;
+    boolean assumeSubject =
+        Utils.HiveAuthenticationParams.AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equals(authParams
+            .get(Utils.HiveAuthenticationParams.AUTH_KERBEROS_AUTH_TYPE));
+    try {
+      if (!Utils.HiveAuthenticationParams.AUTH_SIMPLE.equalsIgnoreCase(authParams.get(Utils.HiveAuthenticationParams.AUTH_TYPE))) {
+        // If Kerberos
+        Map<String, String> saslProps = new HashMap<String, String>();
+        SaslQOP saslQOP = SaslQOP.AUTH;
+        if (authParams.containsKey(Utils.HiveAuthenticationParams.AUTH_PRINCIPAL)) {
+          if (authParams.containsKey(Utils.HiveAuthenticationParams.AUTH_QOP)) {
+            try {
+              saslQOP = SaslQOP.fromString(authParams.get(Utils.HiveAuthenticationParams.AUTH_QOP));
+            } catch (IllegalArgumentException e) {
+              throw new HiveClientException("Invalid " + Utils.HiveAuthenticationParams.AUTH_QOP +
+                  " parameter. " + e.getMessage(), e);
+            }
+          }
+          saslProps.put(Sasl.QOP, saslQOP.toString());
+          saslProps.put(Sasl.SERVER_AUTH, "true");
+          transport = KerberosSaslHelper.getKerberosTransport(
+              authParams.get(Utils.HiveAuthenticationParams.AUTH_PRINCIPAL), host,
+              HiveAuthFactory.getSocketTransport(host, port, 10000), saslProps,
+              assumeSubject);
+        } else {
+          // If there's a delegation token available then use token based connection
+          String tokenStr = getClientDelegationToken(authParams);
+          if (tokenStr != null) {
+            transport = KerberosSaslHelper.getTokenTransport(tokenStr,
+                host, HiveAuthFactory.getSocketTransport(host, port, 10000), saslProps);
+          } else {
+            // we are using PLAIN Sasl connection with user/password
+            String userName = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_USER, Utils.HiveAuthenticationParams.ANONYMOUS_USER);
+            String passwd = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_PASSWD, Utils.HiveAuthenticationParams.ANONYMOUS_USER);
+            // Note: Thrift returns an SSL socket that is already bound to the specified host:port
+            // Therefore an open called on this would be a no-op later
+            // Hence, any TTransportException related to connecting with the peer are thrown here.
+            // Bubbling them up the call hierarchy so that a retry can happen in openTransport,
+            // if dynamic service discovery is configured.
+            if (isSslConnection()) {
+              // get SSL socket
+              String sslTrustStore = authParams.get(Utils.HiveAuthenticationParams.SSL_TRUST_STORE);
+              String sslTrustStorePassword = authParams.get(Utils.HiveAuthenticationParams.SSL_TRUST_STORE_PASSWORD);
+              if (sslTrustStore == null || sslTrustStore.isEmpty()) {
+                transport = HiveAuthFactory.getSSLSocket(host, port, 10000);
+              } else {
+                transport = HiveAuthFactory.getSSLSocket(host, port, 10000,
+                    sslTrustStore, sslTrustStorePassword);
+              }
+            } else {
+              // get non-SSL socket transport
+              transport = HiveAuthFactory.getSocketTransport(host, port, 10000);
+            }
+            // Overlay the SASL transport on top of the base socket transport (SSL or non-SSL)
+            transport = PlainSaslHelper.getPlainTransport(userName, passwd, transport);
+          }
+        }
+      } else {
+        //NOSASL
+        return HiveAuthFactory.getSocketTransport(host, port, 10000);
+      }
+    } catch (SaslException e) {
+      throw new HiveClientException("Could not create secure connection to "
+          + host + ": " + e.getMessage(), e);
+    }
+    return transport;
+  }
+
+  private boolean isSslConnection() {
+    return "true".equalsIgnoreCase(authParams.get(Utils.HiveAuthenticationParams.USE_SSL));
+  }
+
+  // Lookup the delegation token. First in the connection URL, then Configuration
+  private String getClientDelegationToken(Map<String, String> jdbcConnConf) throws HiveClientException {
+    String tokenStr = null;
+    if (Utils.HiveAuthenticationParams.AUTH_TOKEN.equalsIgnoreCase(jdbcConnConf.get(Utils.HiveAuthenticationParams.AUTH_TYPE))) {
+      // check delegation token in job conf if any
+      try {
+        tokenStr = ShimLoader.getHadoopShims().
+            getTokenStrForm(HiveAuthFactory.HS2_CLIENT_TOKEN);
+      } catch (IOException e) {
+        throw new HiveClientException("Error reading token ", e);
+      }
+    }
+    return tokenStr;
+  }
+
+  private String getAuthParamDefault(String key, String defaultValue) {
+    if (authParams.containsKey(key))
+      return authParams.get(key);
+    return defaultValue;
+  }
+
+  private synchronized void openSession() throws HiveClientException {
+    //It's possible to set proxy user configuration here
+    TOpenSessionResp openResp = new HiveCall<TOpenSessionResp>(this) {
+      @Override
+      public TOpenSessionResp body() throws HiveClientException {
+        TOpenSessionReq openReq = new TOpenSessionReq();
+        try {
+          return client.OpenSession(openReq);
+        } catch (TException e) {
+          throw new HiveClientException("Unable to open Hive session", e);
+        }
+
+      }
+    }.call();
+    Utils.verifySuccess(openResp.getStatus(), "Unable to open Hive session");
+
+    protocol = openResp.getServerProtocolVersion();
+    sessHandle = openResp.getSessionHandle();
+    LOG.info("Hive session opened");
+  }
+
+  private synchronized void closeSession() throws HiveClientException {
+    if (sessHandle == null) return;
+    TCloseSessionReq closeReq = new TCloseSessionReq(sessHandle);
+    //It's possible to set proxy user configuration here
+    TCloseSessionResp closeResp = null;
+    try {
+      closeResp = client.CloseSession(closeReq);
+      Utils.verifySuccess(closeResp.getStatus(), "Unable to close Hive session");
+    } catch (TException e) {
+      throw new HiveClientException("Unable to close Hive session", e);
+    }
+
+    sessHandle = null;
+    protocol = null;
+    LOG.info("Hive session closed");
+  }
+
+  public synchronized void closeConnection() throws HiveClientException {
+    if (client == null) return;
+    try {
+      closeSession();
+    } catch (HiveClientException e) {
+      LOG.error("Unable to close Hive session: " + e.getMessage());
+    } finally {
+      transport.close();
+      transport = null;
+      client = null;
+      sessHandle = null;
+      protocol = null;
+    }
+    LOG.info("Connection to Hive closed");
+  }
+
+  /**
+   * Execute query
+   * @param cmd query
+   * @param async wait till query finish?
+   * @return handle of operation
+   * @throws HiveClientException
+   */
+  public TOperationHandle execute(final String cmd, final boolean async) throws HiveClientException {
+    TOperationHandle handle = null;
+    for(final String oneCmd : cmd.split(";")) {
+
+      TExecuteStatementResp execResp = new HiveCall<TExecuteStatementResp>(this) {
+        @Override
+        public TExecuteStatementResp body() throws HiveClientException {
+
+          TExecuteStatementReq execReq = null;
+          execReq = new TExecuteStatementReq(getSessHandle(), oneCmd);
+          execReq.setRunAsync(async);
+          execReq.setConfOverlay(new HashMap<String, String>()); //maybe it's hive configuration? use it, Luke!
+          try {
+            return client.ExecuteStatement(execReq);
+          } catch (TException e) {
+            throw new HiveClientException("Unable to submit statement " + cmd, e);
+          }
+
+        }
+      }.call();
+
+      Utils.verifySuccess(execResp.getStatus(), "Unable to submit statement " + cmd);
+      //TODO: check if status have results
+      handle = execResp.getOperationHandle();
+    }
+    if (handle == null) {
+      throw new HiveClientException("Empty command given", null);
+    }
+    return handle;
+  }
+
+  public TOperationHandle executeAsync(String cmd) throws HiveClientException {
+    return execute(cmd, true);
+  }
+
+  public TOperationHandle executeSync(String cmd) throws HiveClientException {
+    return execute(cmd, false);
+  }
+
+  public String getLogs(TOperationHandle handle) {
+    LogsCursor results = new LogsCursor(this, handle);
+    results.reset(); // we have to read from FIRST line, to get
+                     // logs from beginning on every call this function
+    List<String> logLineList = results.getValuesInColumn(0);
+    StringBuilder log = new StringBuilder();
+    for(String line : logLineList) {
+      log.append(line);
+      log.append('\n');
+    }
+    return log.toString();
+  }
+
+  public Cursor getResults(TOperationHandle handle) {
+    Cursor cursor = new Cursor(this, handle);
+    cursor.reset(); // we have to read from FIRST line, to get
+    // logs from beginning on every call this function
+    return cursor;
+  }
+
+  /**
+   * Retrieve status of operation
+   * @param operationHandle handle
+   * @return thrift status response object
+   * @throws HiveClientException
+   */
+  public TGetOperationStatusResp getOperationStatus(final TOperationHandle operationHandle) throws HiveClientException {
+    return new HiveCall<TGetOperationStatusResp>(this) {
+      @Override
+      public TGetOperationStatusResp body() throws HiveClientException {
+
+        TGetOperationStatusReq statusReq = new TGetOperationStatusReq(operationHandle);
+        try {
+          return client.GetOperationStatus(statusReq);
+        } catch (TException e) {
+          throw new HiveClientException("Unable to fetch operation status", e);
+        }
+
+      }
+    }.call();
+//    transportLock.lock();
+//    try {
+//      return client.GetOperationStatus(statusReq);
+//    } catch (TException e) {
+//      throw new HiveClientException("Unable to fetch operation status", e);
+//    } finally {
+//      transportLock.unlock();
+//    }
+  }
+
+  /**
+   * Cancel operation
+   * @param operationHandle operation handle
+   */
+  public void cancelOperation(final TOperationHandle operationHandle) throws HiveClientException {
+    TCancelOperationResp cancelResp = new HiveCall<TCancelOperationResp>(this) {
+      @Override
+      public TCancelOperationResp body() throws HiveClientException {
+        TCancelOperationReq cancelReq = new TCancelOperationReq(operationHandle);
+        try {
+          return client.CancelOperation(cancelReq);
+        } catch (TException e) {
+          throw new HiveClientException("Unable to cancel operation", null);
+        }
+      }
+    }.call();
+    Utils.verifySuccess(cancelResp.getStatus(), "Unable to cancel operation");
+  }
+
+  public int getPort() {
+    return port;
+  }
+
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  public String getHost() {
+    return host;
+  }
+
+  public void setHost(String host) {
+    this.host = host;
+  }
+
+  public TSessionHandle getSessHandle() throws HiveClientException {
+    if (sessHandle == null)
+      openSession();
+    return sessHandle;
+  }
+
+  public void setSessHandle(TSessionHandle sessHandle) {
+    this.sessHandle = sessHandle;
+  }
+
+  public TCLIService.Client getClient() {
+    return client;
+  }
+
+  public void setClient(TCLIService.Client client) {
+    this.client = client;
+  }
+
+  public TProtocolVersion getProtocol() {
+    return protocol;
+  }
+
+  public void setProtocol(TProtocolVersion protocol) {
+    this.protocol = protocol;
+  }
+
+  public Map<String, String> getAuthParams() {
+    return authParams;
+  }
+
+  public void setAuthParams(Map<String, String> authParams) {
+    this.authParams = authParams;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionPool.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionPool.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionPool.java
new file mode 100644
index 0000000..6d07067
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionPool.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConnectionPool {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(ConnectionPool.class);
+
+  private static Map<String, Connection> viewSingletonObjects = new HashMap<String, Connection>();
+  /**
+   * Returns HdfsApi object specific to instance
+   * @param context View Context instance
+   * @return Hdfs business delegate object
+   */
+  public static Connection getConnection(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), connectToHive(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  private static Connection connectToHive(ViewContext context) {
+    try {
+      return new Connection(getHiveHost(context), Integer.valueOf(getHivePort(context)), getHiveAuthParams(context));
+    } catch (HiveClientException e) {
+      throw new ServiceFormattedException("Couldn't open connection to Hive: " + e.toString(), e);
+    }
+  }
+
+  public static void setInstance(ViewContext context, Connection api) {
+    viewSingletonObjects.put(context.getInstanceName(), api);
+  }
+
+  private static String getHiveHost(ViewContext context) {
+    return context.getProperties().get("hive.host");
+  }
+
+  private static String getHivePort(ViewContext context) {
+    return context.getProperties().get("hive.port");
+  }
+
+  private static Map<String, String> getHiveAuthParams(ViewContext context) {
+    String auth = context.getProperties().get("hive.auth");
+    Map<String, String> params = new HashMap<String, String>();
+    if (auth == null || auth.isEmpty()) {
+      auth = "auth=NOSASL";
+    }
+    for(String param : auth.split(";")) {
+      String[] keyvalue = param.split("=");
+      if (keyvalue.length != 2) {
+        LOG.error("Can not parse authentication param " + param + " in " + auth);
+        continue;
+      }
+      params.put(keyvalue[0], keyvalue[1]);
+    }
+    return params;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Cursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Cursor.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Cursor.java
new file mode 100644
index 0000000..84987f5
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Cursor.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import static org.apache.hive.service.cli.thrift.TCLIServiceConstants.TYPE_NAMES;
+
+import org.apache.ambari.view.hive.utils.BadRequestFormattedException;
+import org.apache.hive.service.cli.RowSet;
+import org.apache.hive.service.cli.RowSetFactory;
+import org.apache.hive.service.cli.thrift.*;
+import org.apache.thrift.TException;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.util.*;
+
+public class Cursor implements Iterator<Row>, Iterable<Row> {
+  private final int FETCH_SIZE = 50;
+
+  private TCLIService.Client client;
+  private TOperationHandle opHandle;
+
+  private RowSet fetched = null;
+  private Iterator<Object[]> fetchedIterator = null;
+  private Connection connection;
+  private boolean resetCursor = false;
+  private ArrayList<ColumnDescription> schema;
+  private long offset;
+  private HashSet<Integer> selectedColumns = new LinkedHashSet<Integer>();
+
+  public Cursor(Connection connection, TOperationHandle opHandle) {
+    this.connection = connection;
+    this.client = connection.getClient();
+    this.opHandle = opHandle;
+  }
+
+  public TOperationHandle getOpHandle() {
+    return opHandle;
+  }
+
+  public void setOpHandle(TOperationHandle opHandle) {
+    this.opHandle = opHandle;
+  }
+
+  private void fetchNextBlock() throws HiveClientException {
+    //fetch another bunch
+    TFetchResultsResp fetchResp = new HiveCall<TFetchResultsResp>(connection) {
+      @Override
+      public TFetchResultsResp body() throws HiveClientException {
+        TFetchOrientation orientation = TFetchOrientation.FETCH_NEXT;
+        if (resetCursor) {
+          orientation = TFetchOrientation.FETCH_FIRST;
+          resetCursor = false;
+          offset = 0;
+        }
+
+        TFetchResultsReq fetchReq = getFetchResultsReq(orientation);
+        try {
+          return client.FetchResults(fetchReq);
+        } catch (TException e) {
+          throw new HiveClientException("Unable to fetch results", e);
+        }
+
+      }
+    }.call();
+    Utils.verifySuccess(fetchResp.getStatus(), "Unable to fetch results");
+    TRowSet results = fetchResp.getResults();
+    fetched = RowSetFactory.create(results, connection.getProtocol());
+    fetchedIterator = fetched.iterator();
+  }
+
+  protected TFetchResultsReq getFetchResultsReq(TFetchOrientation orientation) {
+    return new TFetchResultsReq(opHandle, orientation, FETCH_SIZE);
+  }
+
+  public ArrayList<ColumnDescription> getSchema() throws HiveClientException {
+    if (this.schema == null) {
+      // TODO: extract all HiveCall inline classes to separate files
+      TGetResultSetMetadataResp fetchResp = new HiveCall<TGetResultSetMetadataResp>(connection) {
+        @Override
+        public TGetResultSetMetadataResp body() throws HiveClientException {
+
+          TGetResultSetMetadataReq fetchReq = new TGetResultSetMetadataReq(opHandle);
+          try {
+            return client.GetResultSetMetadata(fetchReq);
+          } catch (TException e) {
+            throw new HiveClientException("Unable to fetch results metadata", e);
+          }
+
+        }
+      }.call();
+      Utils.verifySuccess(fetchResp.getStatus(), "Unable to fetch results metadata");
+      TTableSchema schema = fetchResp.getSchema();
+
+      List<TColumnDesc> thriftColumns = schema.getColumns();
+      ArrayList<ColumnDescription> columnDescriptions = new ArrayList<ColumnDescription>(thriftColumns.size());
+
+      for (TColumnDesc columnDesc : thriftColumns) {
+        String name = columnDesc.getColumnName();
+        String type = TYPE_NAMES.get(columnDesc.getTypeDesc().getTypes().get(0).getPrimitiveEntry().getType());
+        int position = columnDesc.getPosition();
+        columnDescriptions.add(ColumnDescriptionShort.createShortColumnDescription(name, type, position));
+      }
+      if (selectedColumns.size() == 0)
+        this.schema = columnDescriptions;
+      else {
+        ArrayList<ColumnDescription> selectedColumnsSchema = new ArrayList<ColumnDescription>();
+        for (Integer selectedIndex : selectedColumns) {
+          selectedColumnsSchema.add(columnDescriptions.get(selectedIndex));
+        }
+        this.schema = selectedColumnsSchema;
+      }
+    }
+    return this.schema;
+  }
+
+  /**
+   * Get list with all values in one column
+   * @param column column index
+   * @return list of objects in column
+   */
+  public <T> List<T> getValuesInColumn(int column) {
+    LinkedList<T> list = new LinkedList<T>();
+    for (Row row : this) {
+      list.add((T) row.getRow()[column]);
+    }
+    return list;
+  }
+
+  /**
+   * Get logs Result object
+   * @return Result object configured to fetch logs
+   */
+  public Cursor getLogs() {
+    return new LogsCursor(connection, opHandle);
+  }
+
+  public void reset() {
+    fetchedIterator = null;
+    fetched = null;
+    resetCursor = true;
+    offset = 0;
+  }
+
+  @Override
+  public boolean hasNext() {
+    fetchIfNeeded();
+    return fetchedIterator.hasNext();
+  }
+
+  private void fetchIfNeeded() {
+    if (fetchedIterator == null || !fetchedIterator.hasNext()) {
+      try {
+        fetchNextBlock();
+      } catch (HiveClientException e) {
+        throw new HiveClientRuntimeException(e.getMessage(), e);
+      }
+    }
+  }
+
+  @Override
+  public Row next() {
+    if (!hasNext())
+      throw new NoSuchElementException();
+    Row row = new Row(fetchedIterator.next(), selectedColumns);
+    offset ++;
+    return row;
+  }
+
+  @Override
+  public void remove() {
+    throw new NotImplementedException();
+  }
+
+  @Override
+  public Iterator<Row> iterator() {
+    return this;
+  }
+
+//  public int size() {
+//    fetchIfNeeded();
+//    return fetched.numRows();
+//  }
+  public long getOffset() {
+    return offset;
+  }
+
+  public int read(ArrayList<Row> rows, int count) {
+    int read = 0;
+    while(read < count && hasNext()) {
+      rows.add(next());
+      read ++;
+    }
+    return read;
+  }
+
+  public int readRaw(ArrayList<Object[]> rows, int count) {
+    int read = 0;
+    while(read < count && hasNext()) {
+      rows.add(next().getRow());
+      read ++;
+    }
+    return read;
+  }
+
+  public void selectColumns(String columnsRequested) {
+    selectedColumns.clear();
+    if (columnsRequested != null) {
+      for (String columnRequested : columnsRequested.split(",")) {
+        try {
+          selectedColumns.add(Integer.parseInt(columnRequested));
+        } catch (NumberFormatException ex) {
+          throw new BadRequestFormattedException("Columns param should be comma-separated integers", ex);
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/DDLDelegator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/DDLDelegator.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/DDLDelegator.java
new file mode 100644
index 0000000..9cb5a1b
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/DDLDelegator.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.client;
+
+import org.apache.hive.service.cli.thrift.*;
+import org.apache.thrift.TException;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class DDLDelegator {
+  private Connection connection;
+
+  public DDLDelegator(Connection connection) {
+    this.connection = connection;
+  }
+
+  /**
+   * Retrieve list of tables in DB
+   * @param db db name
+   * @return list of table names
+   * @throws HiveClientException
+   */
+  public List<String> getTableList(String db, String like) throws HiveClientException {
+    Cursor cursor = getTableListCursor(db, like);
+    return cursor.getValuesInColumn(0);
+  }
+
+  /**
+   * Retrieve list of tables in DB results set
+   * @param db db name
+   * @return list of table names
+   * @throws HiveClientException
+   */
+   public Cursor getTableListCursor(String db, String like) throws HiveClientException {
+    connection.executeSync(String.format("use %s", db));
+    TOperationHandle handle = connection.executeSync(String.format("show tables like '%s'", like));
+
+    return new Cursor(connection, handle);
+  }
+
+  /**
+   * Retrieve databases
+   * @param like '*' for all
+   * @return list of databases
+   * @throws HiveClientException
+   */
+  public List<String> getDBList(String like) throws HiveClientException {
+    Cursor cursor = getDBListCursor(like);
+    return cursor.getValuesInColumn(0);
+  }
+
+  /**
+   * Retrieve databases results set
+   * @param like '*' for all
+   * @return list of databases
+   * @throws HiveClientException
+   */
+  public Cursor getDBListCursor(String like) throws HiveClientException {
+    TOperationHandle handle = connection.executeSync(String.format("show databases like '%s'", like));
+    return new Cursor(connection, handle);
+  }
+
+  /**
+   * Retrieve table schema
+   * @param db database name
+   * @param table table name
+   * @return schema
+   * @throws HiveClientException
+   */
+  public List<ColumnDescription> getTableDescription(final String db, final String table, String like, boolean extended) throws HiveClientException {
+    List<ColumnDescription> columnDescriptions = new LinkedList<ColumnDescription>();
+    Cursor cursor = getTableDescriptionCursor(db, table, like);
+    for(Row row : cursor) {
+      Object[] rowObjects = row.getRow();
+
+      ColumnDescription columnDescription;
+      if (extended) {
+        //TODO: retrieve sortedBy, clusteredBy, partitioned
+        columnDescription = ColumnDescriptionExtended.createExtendedColumnDescription(
+            (String) rowObjects[3], (String) rowObjects[5], (String) rowObjects[11],
+            false, false, false, (Integer) rowObjects[16]);
+      } else {
+        columnDescription = ColumnDescriptionShort.createShortColumnDescription(
+            (String) rowObjects[3], (String) rowObjects[5], (Integer) rowObjects[16]);
+      }
+      columnDescriptions.add(columnDescription);
+    }
+    return columnDescriptions;
+  }
+
+  /**
+   * Retrieve table schema results set
+   * @param db database name
+   * @param table table name
+   * @return schema
+   * @throws HiveClientException
+   */
+  public Cursor getTableDescriptionCursor(final String db, final String table, String like) throws HiveClientException {
+    if (like == null)
+      like = ".*";
+    else
+      like = ".*" + like + ".*";
+    final String finalLike = like;
+    TGetColumnsResp resp = new HiveCall<TGetColumnsResp>(connection) {
+      @Override
+      public TGetColumnsResp body() throws HiveClientException {
+
+        TGetColumnsReq req = new TGetColumnsReq(conn.getSessHandle());
+        req.setSchemaName(db);
+        req.setTableName(table);
+        req.setColumnName(finalLike);
+        try {
+          return connection.getClient().GetColumns(req);
+        } catch (TException e) {
+          throw new HiveClientException("Unable to get table columns", e);
+        }
+      }
+
+    }.call();
+
+    return new Cursor(connection, resp.getOperationHandle());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveCall.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveCall.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveCall.java
new file mode 100644
index 0000000..c8b43e2
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveCall.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.hive.client;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class HiveCall <T> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(HiveCall.class);
+
+  protected final Connection conn;
+
+  public HiveCall(Connection connection) {
+    this.conn = connection;
+  }
+
+  public abstract T body() throws HiveClientException;
+
+  public T call() throws HiveClientException {
+    T result = null;
+    boolean needRetry = false;
+    int attempts = 0;
+    do {
+      if (needRetry) {
+        needRetry = false;
+        attempts += 1;
+        conn.closeConnection();
+        conn.openConnection();
+      }
+      try {
+
+        synchronized (conn) {
+          result = body();
+        }
+
+      } catch (HiveClientException ex) {
+        Throwable root = ExceptionUtils.getRootCause(ex);
+        if (attempts < 2 && root instanceof TTransportException) {
+          needRetry = true;
+          LOG.error("Retry call because of Transport Exception: " + root.toString());
+          continue;
+        }
+        throw ex;
+      }
+    } while (needRetry);
+    return result;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientException.java
new file mode 100644
index 0000000..9dd04de
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientRuntimeException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientRuntimeException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientRuntimeException.java
new file mode 100644
index 0000000..1393012
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/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.hive.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/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveErrorStatusException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveErrorStatusException.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveErrorStatusException.java
new file mode 100644
index 0000000..7adbe23
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveErrorStatusException.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.hive.client;
+
+import org.apache.hive.service.cli.thrift.TStatusCode;
+
+/**
+ * Some thrift operation done with status 'failed'
+ */
+public class HiveErrorStatusException extends HiveClientException {
+  public HiveErrorStatusException(TStatusCode statusCode, String comment) {
+    super(String.format("Failed with status %s: %s", statusCode, comment), null);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5482d89/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/LogsCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/LogsCursor.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/LogsCursor.java
new file mode 100644
index 0000000..a6705e4
--- /dev/null
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/LogsCursor.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.hive.client;
+
+import org.apache.hive.service.cli.thrift.TFetchOrientation;
+import org.apache.hive.service.cli.thrift.TFetchResultsReq;
+import org.apache.hive.service.cli.thrift.TOperationHandle;
+
+public class LogsCursor extends Cursor {
+  public LogsCursor(Connection connection, TOperationHandle opHandle) {
+    super(connection, opHandle);
+  }
+
+  @Override
+  protected TFetchResultsReq getFetchResultsReq(TFetchOrientation orientation) {
+    TFetchResultsReq req = super.getFetchResultsReq(orientation);
+    req.setFetchType((short) 1);
+    return req;
+  }
+}