Browse Source

AMBARI-13217. Hive View does not support HS2 configured with LDAP Auth (Pallav Kulshreshtha via srimanth)

Srimanth Gunturi 10 years ago
parent
commit
16bcc80e03
30 changed files with 1527 additions and 94 deletions
  1. 20 5
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java
  2. 15 4
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionFactory.java
  3. 31 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveAuthCredentials.java
  4. 27 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveAuthRequiredException.java
  5. 25 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientAuthRequiredException.java
  6. 45 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/UserLocalConnection.java
  7. 33 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/UserLocalHiveAuthCredentials.java
  8. 14 20
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
  9. 282 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java.orig
  10. 53 6
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
  11. 476 0
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java.orig
  12. 12 10
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.java
  13. 6 6
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.java
  14. 0 1
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/viewJobs/JobControllerFactory.java
  15. 3 2
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/viewJobs/JobControllerImpl.java
  16. 2 25
      contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/SharedObjectsFactory.java
  17. 48 0
      contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js
  18. 50 0
      contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js
  19. 1 0
      contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.js
  20. 3 0
      contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
  21. 1 0
      contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js
  22. 1 1
      contrib/views/hive/src/main/resources/ui/hive-web/app/services/database.js
  23. 1 1
      contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
  24. 16 5
      contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java
  25. 63 0
      contrib/views/hive/src/test/java/org/apache/ambari/view/hive/client/ConnectionTest.java
  26. 158 0
      contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobLDAPServiceTest.java
  27. 2 1
      contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java
  28. 129 0
      contrib/views/utils/src/main/java/org/apache/ambari/view/utils/UserLocal.java
  29. 7 4
      contrib/views/utils/src/main/java/org/apache/ambari/view/utils/UserLocalFactory.java
  30. 3 3
      contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ViewUserLocalTest.java

+ 20 - 5
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/Connection.java

@@ -43,7 +43,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map;
 
 
 /**
 /**
- * Holds session
+ * Holds sessions
  */
  */
 public class Connection {
 public class Connection {
   private final static Logger LOG =
   private final static Logger LOG =
@@ -59,12 +59,15 @@ public class Connection {
 
 
   private DDLDelegator ddl;
   private DDLDelegator ddl;
   private String username;
   private String username;
+  private String password;
 
 
-  public Connection(String host, int port, Map<String, String> authParams, String username) throws HiveClientException {
+  public Connection(String host, int port, Map<String, String> authParams, String username, String password)
+      throws HiveClientException, HiveAuthRequiredException {
     this.host = host;
     this.host = host;
     this.port = port;
     this.port = port;
     this.authParams = authParams;
     this.authParams = authParams;
     this.username = username;
     this.username = username;
+    this.password = password;
 
 
     this.sessHandles = new HashMap<String, TSessionHandle>();
     this.sessHandles = new HashMap<String, TSessionHandle>();
 
 
@@ -76,7 +79,7 @@ public class Connection {
     return ddl;
     return ddl;
   }
   }
 
 
-  public synchronized void openConnection() throws HiveClientException {
+  public synchronized void openConnection() throws HiveClientException, HiveAuthRequiredException {
     try {
     try {
       transport = getTransport();
       transport = getTransport();
       transport.open();
       transport.open();
@@ -94,7 +97,7 @@ public class Connection {
    * @return transport
    * @return transport
    * @throws HiveClientException
    * @throws HiveClientException
    */
    */
-  protected TTransport getTransport() throws HiveClientException, TTransportException {
+  protected TTransport getTransport() throws HiveClientException, TTransportException, HiveAuthRequiredException {
     TTransport transport;
     TTransport transport;
     boolean assumeSubject =
     boolean assumeSubject =
         Utils.HiveAuthenticationParams.AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equals(authParams
         Utils.HiveAuthenticationParams.AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equals(authParams
@@ -133,7 +136,7 @@ public class Connection {
           } else {
           } else {
             // we are using PLAIN Sasl connection with user/password
             // we are using PLAIN Sasl connection with user/password
             String userName = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_USER, getUsername());
             String userName = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_USER, getUsername());
-            String passwd = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_PASSWD, Utils.HiveAuthenticationParams.ANONYMOUS_USER);
+            String passwd = getPassword();
             // Note: Thrift returns an SSL socket that is already bound to the specified host:port
             // 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
             // Therefore an open called on this would be a no-op later
             // Hence, any TTransportException related to connecting with the peer are thrown here.
             // Hence, any TTransportException related to connecting with the peer are thrown here.
@@ -168,6 +171,18 @@ public class Connection {
     return transport;
     return transport;
   }
   }
 
 
+  private String getPassword() throws HiveAuthRequiredException {
+    String password = getAuthParamDefault(Utils.HiveAuthenticationParams.AUTH_PASSWD, Utils.HiveAuthenticationParams.ANONYMOUS_USER);
+    if (password.equals("${ask_password}")) {
+      if (this.password == null) {
+        throw new HiveAuthRequiredException();
+      } else {
+        password = this.password;
+      }
+    }
+    return password;
+  }
+
   private boolean isSslConnection() {
   private boolean isSslConnection() {
     return "true".equalsIgnoreCase(authParams.get(Utils.HiveAuthenticationParams.USE_SSL));
     return "true".equalsIgnoreCase(authParams.get(Utils.HiveAuthenticationParams.USE_SSL));
   }
   }

+ 15 - 4
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/ConnectionFactory.java

@@ -21,6 +21,7 @@ package org.apache.ambari.view.hive.client;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.hive.utils.HiveClientFormattedException;
 import org.apache.ambari.view.hive.utils.HiveClientFormattedException;
 import org.apache.ambari.view.hive.utils.ServiceFormattedException;
 import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+import org.apache.ambari.view.utils.UserLocalFactory;
 import org.apache.ambari.view.utils.ambari.AmbariApi;
 import org.apache.ambari.view.utils.ambari.AmbariApi;
 import org.apache.ambari.view.utils.ambari.AmbariApiException;
 import org.apache.ambari.view.utils.ambari.AmbariApiException;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
@@ -31,22 +32,24 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 
 
-public class ConnectionFactory implements IConnectionFactory {
+public class ConnectionFactory implements UserLocalFactory<Connection> {
   private final static Logger LOG =
   private final static Logger LOG =
       LoggerFactory.getLogger(ConnectionFactory.class);
       LoggerFactory.getLogger(ConnectionFactory.class);
   private ViewContext context;
   private ViewContext context;
+  private HiveAuthCredentials credentials;
   private AmbariApi ambariApi;
   private AmbariApi ambariApi;
 
 
-  public ConnectionFactory(ViewContext context) {
+  public ConnectionFactory(ViewContext context, HiveAuthCredentials credentials) {
     this.context = context;
     this.context = context;
+    this.credentials = credentials;
     this.ambariApi = new AmbariApi(context);
     this.ambariApi = new AmbariApi(context);
   }
   }
 
 
   @Override
   @Override
-  public Connection getHiveConnection() {
+  public Connection create() {
     try {
     try {
       return new Connection(getHiveHost(), Integer.valueOf(getHivePort()),
       return new Connection(getHiveHost(), Integer.valueOf(getHivePort()),
-          getHiveAuthParams(), context.getUsername());
+          getHiveAuthParams(), context.getUsername(), getCredentials().getPassword());
     } catch (HiveClientException e) {
     } catch (HiveClientException e) {
       throw new HiveClientFormattedException(e);
       throw new HiveClientFormattedException(e);
     }
     }
@@ -91,4 +94,12 @@ public class ConnectionFactory implements IConnectionFactory {
     }
     }
     return params;
     return params;
   }
   }
+
+  public HiveAuthCredentials getCredentials() {
+    return credentials;
+  }
+
+  public void setCredentials(HiveAuthCredentials credentials) {
+    this.credentials = credentials;
+  }
 }
 }

+ 31 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveAuthCredentials.java

@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+public class HiveAuthCredentials {
+  private String password;
+
+  public String getPassword() {
+    return password;
+  }
+
+  public void setPassword(String password) {
+    this.password = password;
+  }
+}

+ 27 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveAuthRequiredException.java

@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import org.apache.ambari.view.hive.utils.ServiceFormattedException;
+
+public class HiveAuthRequiredException extends ServiceFormattedException {
+  public HiveAuthRequiredException() {
+    super("Hive Password Required", null, 401);
+  }
+}

+ 25 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/HiveClientAuthRequiredException.java

@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+public class HiveClientAuthRequiredException extends Exception {
+  public HiveClientAuthRequiredException(String comment, Exception ex) {
+    super(comment + ((ex == null)?"":(": " + ex.toString())), ex);
+  }
+}

+ 45 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/UserLocalConnection.java

@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive.client;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.UserLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserLocalConnection extends UserLocal<Connection> {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(UserLocalConnection.class);
+
+  public UserLocalConnection() {
+    super(Connection.class);
+  }
+
+  private UserLocal<HiveAuthCredentials> authCredentialsLocal =
+      new UserLocalHiveAuthCredentials();
+
+  @Override
+  protected synchronized Connection initialValue(ViewContext context) {
+    ConnectionFactory hiveConnectionFactory = new ConnectionFactory(context, authCredentialsLocal.get(context));
+    authCredentialsLocal.remove(context);  // we should not store credentials in memory,
+                                          // password is erased after connection established
+    return hiveConnectionFactory.create();
+  }
+
+}

+ 33 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/UserLocalHiveAuthCredentials.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.client;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.UserLocal;
+
+public class UserLocalHiveAuthCredentials extends UserLocal<HiveAuthCredentials> {
+  public UserLocalHiveAuthCredentials() {
+    super(HiveAuthCredentials.class);
+  }
+
+  @Override
+  protected synchronized HiveAuthCredentials initialValue(ViewContext context) {
+    return new HiveAuthCredentials();
+  }
+}

+ 14 - 20
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java

@@ -22,7 +22,7 @@ import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.hive.client.ColumnDescription;
 import org.apache.ambari.view.hive.client.ColumnDescription;
 import org.apache.ambari.view.hive.client.Cursor;
 import org.apache.ambari.view.hive.client.Cursor;
-import org.apache.ambari.view.hive.client.IConnectionFactory;
+import org.apache.ambari.view.hive.client.UserLocalConnection;
 import org.apache.ambari.view.hive.resources.jobs.ResultsPaginationController;
 import org.apache.ambari.view.hive.resources.jobs.ResultsPaginationController;
 import org.apache.ambari.view.hive.utils.BadRequestFormattedException;
 import org.apache.ambari.view.hive.utils.BadRequestFormattedException;
 import org.apache.ambari.view.hive.utils.ServiceFormattedException;
 import org.apache.ambari.view.hive.utils.ServiceFormattedException;
@@ -56,7 +56,7 @@ public class HiveBrowserService {
 
 
   private static final long EXPIRING_TIME = 10*60*1000;  // 10 minutes
   private static final long EXPIRING_TIME = 10*60*1000;  // 10 minutes
   private static Map<String, Cursor> resultsCache;
   private static Map<String, Cursor> resultsCache;
-  private IConnectionFactory connectionFactory;
+  private UserLocalConnection connectionLocal = new UserLocalConnection();
 
 
   public static Map<String, Cursor> getResultsCache() {
   public static Map<String, Cursor> getResultsCache() {
     if (resultsCache == null) {
     if (resultsCache == null) {
@@ -67,12 +67,6 @@ public class HiveBrowserService {
     return resultsCache;
     return resultsCache;
   }
   }
 
 
-  private IConnectionFactory getConnectionFactory() {
-    if (connectionFactory == null)
-      connectionFactory = new SharedObjectsFactory(context);
-    return new SharedObjectsFactory(context);
-  }
-
   /**
   /**
    * Returns list of databases
    * Returns list of databases
    */
    */
@@ -90,8 +84,8 @@ public class HiveBrowserService {
     String curl = null;
     String curl = null;
     try {
     try {
       JSONObject response = new JSONObject();
       JSONObject response = new JSONObject();
-      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-      List<String> tables = getConnectionFactory().getHiveConnection().ddl().getDBList(session, like);
+      TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+      List<String> tables = connectionLocal.get(context).ddl().getDBList(session, like);
       response.put("databases", tables);
       response.put("databases", tables);
       return Response.ok(response).build();
       return Response.ok(response).build();
     } catch (WebApplicationException ex) {
     } catch (WebApplicationException ex) {
@@ -127,8 +121,8 @@ public class HiveBrowserService {
                   new Callable<Cursor>() {
                   new Callable<Cursor>() {
                     @Override
                     @Override
                     public Cursor call() throws Exception {
                     public Cursor call() throws Exception {
-                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-                      return getConnectionFactory().getHiveConnection().ddl().getDBListCursor(session, finalLike);
+                      TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+                      return connectionLocal.get(context).ddl().getDBListCursor(session, finalLike);
                     }
                     }
                   }).build();
                   }).build();
     } catch (WebApplicationException ex) {
     } catch (WebApplicationException ex) {
@@ -158,8 +152,8 @@ public class HiveBrowserService {
     String curl = null;
     String curl = null;
     try {
     try {
       JSONObject response = new JSONObject();
       JSONObject response = new JSONObject();
-      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-      List<String> tables = getConnectionFactory().getHiveConnection().ddl().getTableList(session, db, like);
+      TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+      List<String> tables = connectionLocal.get(context).ddl().getTableList(session, db, like);
       response.put("tables", tables);
       response.put("tables", tables);
       response.put("database", db);
       response.put("database", db);
       return Response.ok(response).build();
       return Response.ok(response).build();
@@ -197,8 +191,8 @@ public class HiveBrowserService {
                   new Callable<Cursor>() {
                   new Callable<Cursor>() {
                     @Override
                     @Override
                     public Cursor call() throws Exception {
                     public Cursor call() throws Exception {
-                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-                      Cursor cursor = getConnectionFactory().getHiveConnection().ddl().getTableListCursor(session, db, finalLike);
+                      TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+                      Cursor cursor = connectionLocal.get(context).ddl().getTableListCursor(session, db, finalLike);
                       cursor.selectColumns(requestedColumns);
                       cursor.selectColumns(requestedColumns);
                       return cursor;
                       return cursor;
                     }
                     }
@@ -227,8 +221,8 @@ public class HiveBrowserService {
     String curl = null;
     String curl = null;
     try {
     try {
       JSONObject response = new JSONObject();
       JSONObject response = new JSONObject();
-      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-      List<ColumnDescription> columnDescriptions = getConnectionFactory().getHiveConnection().ddl()
+      TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+      List<ColumnDescription> columnDescriptions = connectionLocal.get(context).ddl()
           .getTableDescription(session, db, table, like, extendedTableDescription);
           .getTableDescription(session, db, table, like, extendedTableDescription);
       response.put("columns", columnDescriptions);
       response.put("columns", columnDescriptions);
       response.put("database", db);
       response.put("database", db);
@@ -264,8 +258,8 @@ public class HiveBrowserService {
               new Callable<Cursor>() {
               new Callable<Cursor>() {
                 @Override
                 @Override
                 public Cursor call() throws Exception {
                 public Cursor call() throws Exception {
-                  TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-                  Cursor cursor = getConnectionFactory().getHiveConnection().ddl().
+                  TSessionHandle session = connectionLocal.get(context).getOrCreateSessionByTag("DDL");
+                  Cursor cursor = connectionLocal.get(context).ddl().
                       getTableDescriptionCursor(session, db, table, like);
                       getTableDescriptionCursor(session, db, table, like);
                   cursor.selectColumns(requestedColumns);
                   cursor.selectColumns(requestedColumns);
                   return cursor;
                   return cursor;

+ 282 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java.orig

@@ -0,0 +1,282 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive.client.ColumnDescription;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.client.IConnectionFactory;
+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.ambari.view.hive.utils.SharedObjectsFactory;
+import org.apache.commons.collections4.map.PassiveExpiringMap;
+import org.apache.hive.service.cli.thrift.TSessionHandle;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+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;
+  private IConnectionFactory connectionFactory;
+
+  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;
+  }
+
+  private IConnectionFactory getConnectionFactory() {
+    if (connectionFactory == null)
+      connectionFactory = new SharedObjectsFactory(context);
+    return new SharedObjectsFactory(context);
+  }
+
+  /**
+   * 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();
+      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+      List<String> tables = getConnectionFactory().getHiveConnection().ddl().getDBList(session, 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("format") String format,
+                            @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, format,
+                  new Callable<Cursor>() {
+                    @Override
+                    public Cursor call() throws Exception {
+                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+                      return getConnectionFactory().getHiveConnection().ddl().getDBListCursor(session, 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();
+      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+      List<String> tables = getConnectionFactory().getHiveConnection().ddl().getTableList(session, 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("format") String format,
+                                   @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, format,
+                  new Callable<Cursor>() {
+                    @Override
+                    public Cursor call() throws Exception {
+                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+                      Cursor cursor = getConnectionFactory().getHiveConnection().ddl().getTableListCursor(session, 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();
+      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+      List<ColumnDescription> columnDescriptions = getConnectionFactory().getHiveConnection().ddl()
+          .getTableDescription(session, 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("format") String format,
+                                         @QueryParam("columns") final String requestedColumns) {
+    String curl = null;
+    try {
+      return ResultsPaginationController.getInstance(context)
+          .request(db + ":tables:" + table + ":columns", searchId, false, fromBeginning, count, format,
+              new Callable<Cursor>() {
+                @Override
+                public Cursor call() throws Exception {
+                  TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+                  Cursor cursor = getConnectionFactory().getHiveConnection().ddl().
+                      getTableDescriptionCursor(session, 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);
+    }
+  }
+}

+ 53 - 6
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java

@@ -21,9 +21,7 @@ package org.apache.ambari.view.hive.resources.jobs;
 import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.hive.BaseService;
 import org.apache.ambari.view.hive.BaseService;
 import org.apache.ambari.view.hive.backgroundjobs.BackgroundJobController;
 import org.apache.ambari.view.hive.backgroundjobs.BackgroundJobController;
-import org.apache.ambari.view.hive.client.Connection;
-import org.apache.ambari.view.hive.client.Cursor;
-import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.client.*;
 import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
 import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.IATSParser;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.IATSParser;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.*;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.*;
@@ -60,8 +58,10 @@ public class JobService extends BaseService {
   @Inject
   @Inject
   ViewResourceHandler handler;
   ViewResourceHandler handler;
 
 
-  protected JobResourceManager resourceManager;
+  private JobResourceManager resourceManager;
   private IOperationHandleResourceManager opHandleResourceManager;
   private IOperationHandleResourceManager opHandleResourceManager;
+  private UserLocalConnection connectionLocal = new UserLocalConnection();
+
   protected final static Logger LOG =
   protected final static Logger LOG =
       LoggerFactory.getLogger(JobService.class);
       LoggerFactory.getLogger(JobService.class);
   private Aggregator aggregator;
   private Aggregator aggregator;
@@ -421,6 +421,46 @@ public class JobService extends BaseService {
     }
     }
   }
   }
 
 
+  /**
+   * Set password and connect to Hive
+   */
+  @POST
+  @Path("auth")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response setupPassword(AuthRequest request) {
+    try {
+      HiveAuthCredentials authCredentials = new HiveAuthCredentials();
+      authCredentials.setPassword(request.password);
+      new UserLocalHiveAuthCredentials().set(authCredentials, context);
+
+      connectionLocal.remove(context);  // force reconnect on next get
+      connectionLocal.get(context);
+      return Response.ok().status(200).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Remove connection credentials
+   */
+  @DELETE
+  @Path("auth")
+  public Response removePassword() {
+    try {
+      new UserLocalHiveAuthCredentials().remove(context);
+      connectionLocal.remove(context);  // force reconnect on next get
+      return Response.ok().status(200).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+
   /**
   /**
    * Invalidate session
    * Invalidate session
    */
    */
@@ -428,7 +468,7 @@ public class JobService extends BaseService {
   @Path("sessions/{sessionTag}")
   @Path("sessions/{sessionTag}")
   public Response invalidateSession(@PathParam("sessionTag") String sessionTag) {
   public Response invalidateSession(@PathParam("sessionTag") String sessionTag) {
     try {
     try {
-      Connection connection = getSharedObjectsFactory().getHiveConnection();
+      Connection connection = connectionLocal.get(context);
       connection.invalidateSessionByTag(sessionTag);
       connection.invalidateSessionByTag(sessionTag);
       return Response.ok().build();
       return Response.ok().build();
     } catch (WebApplicationException ex) {
     } catch (WebApplicationException ex) {
@@ -446,7 +486,7 @@ public class JobService extends BaseService {
   @Produces(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Response sessionStatus(@PathParam("sessionTag") String sessionTag) {
   public Response sessionStatus(@PathParam("sessionTag") String sessionTag) {
     try {
     try {
-      Connection connection = getSharedObjectsFactory().getHiveConnection();
+      Connection connection = connectionLocal.get(context);
 
 
       JSONObject session = new JSONObject();
       JSONObject session = new JSONObject();
       session.put("sessionTag", sessionTag);
       session.put("sessionTag", sessionTag);
@@ -473,4 +513,11 @@ public class JobService extends BaseService {
   public static class JobRequest {
   public static class JobRequest {
     public JobImpl job;
     public JobImpl job;
   }
   }
+
+  /**
+   * Wrapper for authentication json mapping
+   */
+  public static class AuthRequest {
+    public String password;
+  }
 }
 }

+ 476 - 0
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java.orig

@@ -0,0 +1,476 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.ViewResourceHandler;
+import org.apache.ambari.view.hive.BaseService;
+import org.apache.ambari.view.hive.backgroundjobs.BackgroundJobController;
+import org.apache.ambari.view.hive.client.Connection;
+import org.apache.ambari.view.hive.client.Cursor;
+import org.apache.ambari.view.hive.client.HiveClientException;
+import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.resources.jobs.atsJobs.IATSParser;
+import org.apache.ambari.view.hive.resources.jobs.viewJobs.*;
+import org.apache.ambari.view.hive.utils.*;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+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;
+  private IOperationHandleResourceManager opHandleResourceManager;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(JobService.class);
+  private Aggregator aggregator;
+
+  protected synchronized JobResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      SharedObjectsFactory connectionsFactory = getSharedObjectsFactory();
+      resourceManager = new JobResourceManager(connectionsFactory, context);
+    }
+    return resourceManager;
+  }
+
+  protected IOperationHandleResourceManager getOperationHandleResourceManager() {
+    if (opHandleResourceManager == null) {
+      opHandleResourceManager = new OperationHandleResourceManager(getSharedObjectsFactory());
+    }
+    return opHandleResourceManager;
+  }
+
+  protected Aggregator getAggregator() {
+    if (aggregator == null) {
+      IATSParser atsParser = getSharedObjectsFactory().getATSParser();
+      aggregator = new Aggregator(getResourceManager(), getOperationHandleResourceManager(), atsParser);
+    }
+    return aggregator;
+  }
+
+  protected void setAggregator(Aggregator aggregator) {
+    this.aggregator = aggregator;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{jobId}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("jobId") String jobId) {
+    try {
+      JobController jobController = getResourceManager().readController(jobId);
+
+      JSONObject jsonJob = jsonObjectFromJob(jobController);
+
+      return Response.ok(jsonJob).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  private JSONObject jsonObjectFromJob(JobController jobController) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+    Job hiveJob = jobController.getJobPOJO();
+
+    Job mergedJob;
+    try {
+      mergedJob = getAggregator().readATSJob(hiveJob);
+    } catch (ItemNotFound itemNotFound) {
+      throw new ServiceFormattedException("E010 Job not found", itemNotFound);
+    }
+    Map createdJobMap = PropertyUtils.describe(mergedJob);
+    createdJobMap.remove("class"); // no need to show Bean class on client
+
+    JSONObject jobJson = new JSONObject();
+    jobJson.put("job", createdJobMap);
+    return jobJson;
+  }
+
+  /**
+   * Get job results in csv format
+   */
+  @GET
+  @Path("{jobId}/results/csv")
+  @Produces("text/csv")
+  public Response getResultsCSV(@PathParam("jobId") String jobId,
+                                @Context HttpServletResponse response,
+                                @QueryParam("fileName") String fileName,
+                                @QueryParam("columns") final String requestedColumns) {
+    try {
+      JobController jobController = getResourceManager().readController(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 {
+
+            try {
+              csvPrinter.printRecord(resultSet.getHeadersRow().getRow());
+            } catch (HiveClientException e) {
+              LOG.error("Error on reading results header", e);
+            }
+
+            while (resultSet.hasNext()) {
+              csvPrinter.printRecord(resultSet.next().getRow());
+              writer.flush();
+            }
+          } finally {
+            writer.close();
+          }
+        }
+      };
+
+      if (fileName == null || fileName.isEmpty()) {
+        fileName = "results.csv";
+      }
+
+      return Response.ok(stream).
+          header("Content-Disposition", String.format("attachment; filename=\"%s\"", fileName)).
+          build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (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(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 = getSharedObjectsFactory().getHdfsApi().create(targetFile, true);
+              Writer writer = new BufferedWriter(new OutputStreamWriter(stream));
+              CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT);
+              try {
+                while (resultSet.hasNext() && !Thread.currentThread().isInterrupted()) {
+                  csvPrinter.printRecord(resultSet.next().getRow());
+                  writer.flush();
+                }
+              } finally {
+                writer.close();
+              }
+              stream.close();
+
+            } catch (IOException e) {
+              throw new ServiceFormattedException("F010 Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            } catch (InterruptedException e) {
+              throw new ServiceFormattedException("F010 Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            } catch (ItemNotFound itemNotFound) {
+              throw new NotFoundFormattedException("E020 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("format") String format,
+                             @QueryParam("columns") final String requestedColumns) {
+    try {
+      final JobController jobController = getResourceManager().readController(jobId);
+      if (!jobController.hasResults()) {
+        return ResultsPaginationController.emptyResponse().build();
+      }
+
+      return ResultsPaginationController.getInstance(context)
+           .request(jobId, searchId, true, fromBeginning, count, format,
+               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);
+    }
+  }
+
+  /**
+   * Get progress info
+   */
+  @GET
+  @Path("{jobId}/progress")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getProgress(@PathParam("jobId") String jobId) {
+    try {
+      final JobController jobController = getResourceManager().readController(jobId);
+
+      ProgressRetriever.Progress progress = new ProgressRetriever(jobController.getJob(), getSharedObjectsFactory()).
+          getProgress();
+
+      return Response.ok(progress).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{id}")
+  public Response delete(@PathParam("id") String id,
+                         @QueryParam("remove") final String remove) {
+    try {
+      JobController jobController;
+      try {
+        jobController = getResourceManager().readController(id);
+      } catch (ItemNotFound itemNotFound) {
+        throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+      }
+      jobController.cancel();
+      if (remove != null && remove.compareTo("true") == 0) {
+        getResourceManager().delete(id);
+      }
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get all Jobs
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all job");
+      List<Job> allJobs = getAggregator().readAll(context.getUsername());
+      for(Job job : allJobs) {
+        job.setSessionTag(null);
+      }
+
+      JSONObject object = new JSONObject();
+      object.put("jobs", allJobs);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create job
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(JobRequest request, @Context HttpServletResponse response,
+                         @Context UriInfo ui) {
+    try {
+      Map jobInfo = PropertyUtils.describe(request.job);
+      Job job = new JobImpl(jobInfo);
+      getResourceManager().create(job);
+
+      JobController createdJobController = getResourceManager().readController(job.getId());
+      createdJobController.submit();
+      getResourceManager().saveIfModified(createdJobController);
+
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), job.getId()));
+
+      JSONObject jobObject = jsonObjectFromJob(createdJobController);
+
+      return Response.ok(jobObject).status(201).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Invalidate session
+   */
+  @DELETE
+  @Path("sessions/{sessionTag}")
+  public Response invalidateSession(@PathParam("sessionTag") String sessionTag) {
+    try {
+      Connection connection = getSharedObjectsFactory().getHiveConnection();
+      connection.invalidateSessionByTag(sessionTag);
+      return Response.ok().build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Session status
+   */
+  @GET
+  @Path("sessions/{sessionTag}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response sessionStatus(@PathParam("sessionTag") String sessionTag) {
+    try {
+      Connection connection = getSharedObjectsFactory().getHiveConnection();
+
+      JSONObject session = new JSONObject();
+      session.put("sessionTag", sessionTag);
+      try {
+        connection.getSessionByTag(sessionTag);
+        session.put("actual", true);
+      } catch (HiveClientException ex) {
+        session.put("actual", false);
+      }
+
+      JSONObject status = new JSONObject();
+      status.put("session", session);
+      return Response.ok(status).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class JobRequest {
+    public JobImpl job;
+  }
+}

+ 12 - 10
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleController.java

@@ -19,10 +19,10 @@
 package org.apache.ambari.view.hive.resources.jobs;
 package org.apache.ambari.view.hive.resources.jobs;
 
 
 
 
+import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.hive.client.Cursor;
 import org.apache.ambari.view.hive.client.Cursor;
 import org.apache.ambari.view.hive.client.HiveClientException;
 import org.apache.ambari.view.hive.client.HiveClientException;
-import org.apache.ambari.view.hive.client.IConnectionFactory;
-import org.apache.ambari.view.hive.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive.client.UserLocalConnection;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive.utils.HiveClientFormattedException;
 import org.apache.ambari.view.hive.utils.HiveClientFormattedException;
 import org.apache.hive.service.cli.thrift.TGetOperationStatusResp;
 import org.apache.hive.service.cli.thrift.TGetOperationStatusResp;
@@ -33,14 +33,16 @@ import org.slf4j.LoggerFactory;
 public class OperationHandleController {
 public class OperationHandleController {
   private final static Logger LOG =
   private final static Logger LOG =
       LoggerFactory.getLogger(OperationHandleController.class);
       LoggerFactory.getLogger(OperationHandleController.class);
-  private final IConnectionFactory connectionsFabric;
-
   private final TOperationHandle operationHandle;
   private final TOperationHandle operationHandle;
+  private ViewContext context;
   private final StoredOperationHandle storedOperationHandle;
   private final StoredOperationHandle storedOperationHandle;
   private final IOperationHandleResourceManager operationHandlesStorage;
   private final IOperationHandleResourceManager operationHandlesStorage;
 
 
-  public OperationHandleController(IConnectionFactory connectionsFabric, StoredOperationHandle storedOperationHandle, IOperationHandleResourceManager operationHandlesStorage) {
-    this.connectionsFabric = connectionsFabric;
+  protected UserLocalConnection connectionLocal = new UserLocalConnection();
+
+  public OperationHandleController(ViewContext context, StoredOperationHandle storedOperationHandle,
+                                   IOperationHandleResourceManager operationHandlesStorage) {
+    this.context = context;
     this.storedOperationHandle = storedOperationHandle;
     this.storedOperationHandle = storedOperationHandle;
     this.operationHandle = storedOperationHandle.toTOperationHandle();
     this.operationHandle = storedOperationHandle.toTOperationHandle();
     this.operationHandlesStorage = operationHandlesStorage;
     this.operationHandlesStorage = operationHandlesStorage;
@@ -51,7 +53,7 @@ public class OperationHandleController {
   }
   }
 
 
   public OperationStatus getOperationStatus() throws NoOperationStatusSetException, HiveClientException {
   public OperationStatus getOperationStatus() throws NoOperationStatusSetException, HiveClientException {
-    TGetOperationStatusResp statusResp = connectionsFabric.getHiveConnection().getOperationStatus(operationHandle);
+    TGetOperationStatusResp statusResp = connectionLocal.get(context).getOperationStatus(operationHandle);
 
 
     if (!statusResp.isSetOperationState()) {
     if (!statusResp.isSetOperationState()) {
       throw new NoOperationStatusSetException();
       throw new NoOperationStatusSetException();
@@ -95,7 +97,7 @@ public class OperationHandleController {
 
 
   public void cancel() {
   public void cancel() {
     try {
     try {
-      connectionsFabric.getHiveConnection().cancelOperation(operationHandle);
+      connectionLocal.get(context).cancelOperation(operationHandle);
     } catch (HiveClientException e) {
     } catch (HiveClientException e) {
       throw new HiveClientFormattedException(e);
       throw new HiveClientFormattedException(e);
     }
     }
@@ -108,7 +110,7 @@ public class OperationHandleController {
   public String getLogs() {
   public String getLogs() {
     String logs;
     String logs;
     try {
     try {
-      logs = connectionsFabric.getHiveConnection().getLogs(operationHandle);
+      logs = connectionLocal.get(context).getLogs(operationHandle);
     } catch (HiveClientFormattedException ex) {
     } catch (HiveClientFormattedException ex) {
       logs = "";
       logs = "";
       LOG.info(String.format("Logs are not available yet for job #%s [%s]\n%s",
       LOG.info(String.format("Logs are not available yet for job #%s [%s]\n%s",
@@ -118,7 +120,7 @@ public class OperationHandleController {
   }
   }
 
 
   public Cursor getResults() {
   public Cursor getResults() {
-    return connectionsFabric.getHiveConnection().getResults(operationHandle);
+    return connectionLocal.get(context).getResults(operationHandle);
   }
   }
 
 
   public boolean hasResults() {
   public boolean hasResults() {

+ 6 - 6
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/OperationHandleControllerFactory.java

@@ -18,22 +18,22 @@
 
 
 package org.apache.ambari.view.hive.resources.jobs;
 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.ambari.view.hive.persistence.utils.ItemNotFound;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive.utils.SharedObjectsFactory;
 import org.apache.ambari.view.hive.utils.SharedObjectsFactory;
-import org.apache.hive.service.cli.thrift.TOperationHandle;
 
 
 public class OperationHandleControllerFactory {
 public class OperationHandleControllerFactory {
-  private SharedObjectsFactory connectionsFabric;
   private IOperationHandleResourceManager operationHandlesStorage;
   private IOperationHandleResourceManager operationHandlesStorage;
+  private ViewContext context;
 
 
-  public OperationHandleControllerFactory(SharedObjectsFactory connectionsFabric) {
-    this.connectionsFabric = connectionsFabric;
-    operationHandlesStorage = new OperationHandleResourceManager(connectionsFabric);
+  public OperationHandleControllerFactory(ViewContext context, SharedObjectsFactory storageFactory) {
+    this.context = context;
+    this.operationHandlesStorage = new OperationHandleResourceManager(storageFactory);
   }
   }
 
 
   public OperationHandleController createControllerForHandle(StoredOperationHandle storedOperationHandle) {
   public OperationHandleController createControllerForHandle(StoredOperationHandle storedOperationHandle) {
-    return new OperationHandleController(connectionsFabric, storedOperationHandle, operationHandlesStorage);
+    return new OperationHandleController(context, storedOperationHandle, operationHandlesStorage);
   }
   }
 
 
   public OperationHandleController getHandleForJob(Job job) throws ItemNotFound {
   public OperationHandleController getHandleForJob(Job job) throws ItemNotFound {

+ 0 - 1
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/viewJobs/JobControllerFactory.java

@@ -33,7 +33,6 @@ public class JobControllerFactory implements IJobControllerFactory {
   @Override
   @Override
   public JobController createControllerForJob(Job job) {
   public JobController createControllerForJob(Job job) {
     return new JobControllerImpl(context, job,
     return new JobControllerImpl(context, job,
-        sharedObjectsFactory.getHiveConnectionController(),
         sharedObjectsFactory.getOperationHandleControllerFactory(),
         sharedObjectsFactory.getOperationHandleControllerFactory(),
         sharedObjectsFactory.getSavedQueryResourceManager(),
         sharedObjectsFactory.getSavedQueryResourceManager(),
         sharedObjectsFactory.getATSParser(),
         sharedObjectsFactory.getATSParser(),

+ 3 - 2
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/viewJobs/JobControllerImpl.java

@@ -58,7 +58,6 @@ public class JobControllerImpl implements JobController, ModifyNotificationDeleg
    * Warning: Create JobControllers ONLY using JobControllerFactory!
    * Warning: Create JobControllers ONLY using JobControllerFactory!
    */
    */
   public JobControllerImpl(ViewContext context, Job job,
   public JobControllerImpl(ViewContext context, Job job,
-                           ConnectionController hiveConnection,
                            OperationHandleControllerFactory opHandleControllerFactory,
                            OperationHandleControllerFactory opHandleControllerFactory,
                            SavedQueryResourceManager savedQueryResourceManager,
                            SavedQueryResourceManager savedQueryResourceManager,
                            IATSParser atsParser,
                            IATSParser atsParser,
@@ -66,10 +65,12 @@ public class JobControllerImpl implements JobController, ModifyNotificationDeleg
     this.context = context;
     this.context = context;
     setJobPOJO(job);
     setJobPOJO(job);
     this.opHandleControllerFactory = opHandleControllerFactory;
     this.opHandleControllerFactory = opHandleControllerFactory;
-    this.hiveConnection = hiveConnection;
     this.savedQueryResourceManager = savedQueryResourceManager;
     this.savedQueryResourceManager = savedQueryResourceManager;
     this.atsParser = atsParser;
     this.atsParser = atsParser;
     this.hdfsApi = hdfsApi;
     this.hdfsApi = hdfsApi;
+
+    UserLocalConnection connectionLocal = new UserLocalConnection();
+    this.hiveConnection = new ConnectionController(opHandleControllerFactory, connectionLocal.get(context));
   }
   }
 
 
   public String getQueryForJob() {
   public String getQueryForJob() {

+ 2 - 25
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/utils/SharedObjectsFactory.java

@@ -20,12 +20,9 @@ package org.apache.ambari.view.hive.utils;
 
 
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.hive.client.Connection;
 import org.apache.ambari.view.hive.client.Connection;
-import org.apache.ambari.view.hive.client.ConnectionFactory;
-import org.apache.ambari.view.hive.client.IConnectionFactory;
 import org.apache.ambari.view.hive.persistence.IStorageFactory;
 import org.apache.ambari.view.hive.persistence.IStorageFactory;
 import org.apache.ambari.view.hive.persistence.Storage;
 import org.apache.ambari.view.hive.persistence.Storage;
 import org.apache.ambari.view.hive.persistence.utils.StorageFactory;
 import org.apache.ambari.view.hive.persistence.utils.StorageFactory;
-import org.apache.ambari.view.hive.resources.jobs.ConnectionController;
 import org.apache.ambari.view.hive.resources.jobs.OperationHandleControllerFactory;
 import org.apache.ambari.view.hive.resources.jobs.OperationHandleControllerFactory;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.ATSParser;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.ATSParser;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.ATSParserFactory;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.ATSParserFactory;
@@ -48,12 +45,11 @@ import java.util.Map;
  * e.g. user 'admin' using view instance 'HIVE1' will use one connection, another user
  * e.g. user 'admin' using view instance 'HIVE1' will use one connection, another user
  * will use different connection.
  * will use different connection.
  */
  */
-public class SharedObjectsFactory implements IStorageFactory, IConnectionFactory {
+public class SharedObjectsFactory implements IStorageFactory {
   protected final static Logger LOG =
   protected final static Logger LOG =
       LoggerFactory.getLogger(SharedObjectsFactory.class);
       LoggerFactory.getLogger(SharedObjectsFactory.class);
 
 
   private ViewContext context;
   private ViewContext context;
-  private final IConnectionFactory hiveConnectionFactory;
   private final IStorageFactory storageFactory;
   private final IStorageFactory storageFactory;
   private final ATSParserFactory atsParserFactory;
   private final ATSParserFactory atsParserFactory;
   private final RMParserFactory rmParserFactory;
   private final RMParserFactory rmParserFactory;
@@ -62,14 +58,12 @@ public class SharedObjectsFactory implements IStorageFactory, IConnectionFactory
 
 
   public SharedObjectsFactory(ViewContext context) {
   public SharedObjectsFactory(ViewContext context) {
     this.context = context;
     this.context = context;
-    this.hiveConnectionFactory = new ConnectionFactory(context);
     this.storageFactory = new StorageFactory(context);
     this.storageFactory = new StorageFactory(context);
     this.atsParserFactory = new ATSParserFactory(context);
     this.atsParserFactory = new ATSParserFactory(context);
     this.rmParserFactory = new RMParserFactory(context);
     this.rmParserFactory = new RMParserFactory(context);
 
 
     synchronized (localObjects) {
     synchronized (localObjects) {
       if (localObjects.size() == 0) {
       if (localObjects.size() == 0) {
-        localObjects.put(Connection.class, new HashMap<String, Object>());
         localObjects.put(OperationHandleControllerFactory.class, new HashMap<String, Object>());
         localObjects.put(OperationHandleControllerFactory.class, new HashMap<String, Object>());
         localObjects.put(Storage.class, new HashMap<String, Object>());
         localObjects.put(Storage.class, new HashMap<String, Object>());
         localObjects.put(IJobControllerFactory.class, new HashMap<String, Object>());
         localObjects.put(IJobControllerFactory.class, new HashMap<String, Object>());
@@ -81,28 +75,11 @@ public class SharedObjectsFactory implements IStorageFactory, IConnectionFactory
     }
     }
   }
   }
 
 
-  /**
-   * Returns Connection object specific to unique tag
-   * @return Hdfs business delegate object
-   */
-  @Override
-  public Connection getHiveConnection() {
-    if (!localObjects.get(Connection.class).containsKey(getTagName())) {
-      Connection newConnection = hiveConnectionFactory.getHiveConnection();
-      localObjects.get(Connection.class).put(getTagName(), newConnection);
-    }
-    return (Connection) localObjects.get(Connection.class).get(getTagName());
-  }
-
-  public ConnectionController getHiveConnectionController() {
-    return new ConnectionController(getOperationHandleControllerFactory(), getHiveConnection());
-  }
-
   // =============================
   // =============================
 
 
   public OperationHandleControllerFactory getOperationHandleControllerFactory() {
   public OperationHandleControllerFactory getOperationHandleControllerFactory() {
     if (!localObjects.get(OperationHandleControllerFactory.class).containsKey(getTagName()))
     if (!localObjects.get(OperationHandleControllerFactory.class).containsKey(getTagName()))
-      localObjects.get(OperationHandleControllerFactory.class).put(getTagName(), new OperationHandleControllerFactory(this));
+      localObjects.get(OperationHandleControllerFactory.class).put(getTagName(), new OperationHandleControllerFactory(context, this));
     return (OperationHandleControllerFactory) localObjects.get(OperationHandleControllerFactory.class).get(getTagName());
     return (OperationHandleControllerFactory) localObjects.get(OperationHandleControllerFactory.class).get(getTagName());
   }
   }
 
 

+ 48 - 0
contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/databases.js

@@ -155,6 +155,12 @@ export default Ember.Controller.extend({
       self.set('isLoading');
       self.set('isLoading');
     }).catch(function (error) {
     }).catch(function (error) {
       self._handleError(error);
       self._handleError(error);
+
+      if(error.status == 401) {
+         self.send('passwordLDAPDB');
+      }
+
+
     });
     });
   }.on('init'),
   }.on('init'),
 
 
@@ -163,6 +169,48 @@ export default Ember.Controller.extend({
       this.getDatabases();
       this.getDatabases();
     },
     },
 
 
+    passwordLDAPDB: function(){
+      var self = this,
+          defer = Ember.RSVP.defer();
+
+      self.getDatabases = this.getDatabases;
+
+      this.send('openModal', 'modal-save', {
+        heading: "modals.authenticationLDAP.heading",
+        text:"",
+        type: "password",
+        defer: defer
+      });
+
+      defer.promise.then(function (text) {
+        // make a post call with the given ldap password.
+        var password = text;
+        var pathName = window.location.pathname;
+        var pathNameArray = pathName.split("/");
+        var hiveViewVersion = pathNameArray[3];
+        var hiveViewName = pathNameArray[4];
+        var ldapAuthURL = "/api/v1/views/HIVE/versions/"+ hiveViewVersion + "/instances/" + hiveViewName + "/jobs/auth";
+
+        $.ajax({
+          url: ldapAuthURL,
+          dataType: "json",
+          type: 'post',
+          headers: {'X-Requested-With': 'XMLHttpRequest', 'X-Requested-By': 'ambari'},
+          contentType: 'application/json',
+          data: JSON.stringify({ "password" : password}),
+          success: function( data, textStatus, jQxhr ){
+            console.log( "LDAP done: " + data );
+            self.getDatabases();
+          },
+          error: function( jqXhr, textStatus, errorThrown ){
+            console.log( "LDAP fail: " + errorThrown );
+            self.get('notifyService').error( "Wrong Credentials." );
+          }
+        });
+
+      });
+    },
+
     loadSampleData: function (tableName, database) {
     loadSampleData: function (tableName, database) {
       var self = this;
       var self = this;
       this.send('addQuery', Ember.I18n.t('titles.tableSample', { tableName: tableName }));
       this.send('addQuery', Ember.I18n.t('titles.tableSample', { tableName: tableName }));

+ 50 - 0
contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/index.js

@@ -227,6 +227,11 @@ export default Ember.Controller.extend({
       self.set('jobSaveSucceeded');
       self.set('jobSaveSucceeded');
       originalModel.set('isRunning', undefined);
       originalModel.set('isRunning', undefined);
       defer.reject(err);
       defer.reject(err);
+
+      if(err.status == 401) {
+          self.send('passwordLDAP', job, originalModel);
+      }
+
     };
     };
 
 
     job.save().then(function () {
     job.save().then(function () {
@@ -477,6 +482,51 @@ export default Ember.Controller.extend({
   }.observes('model', 'model.status'),
   }.observes('model', 'model.status'),
 
 
   actions: {
   actions: {
+    passwordLDAP: function(){
+      var job = arguments[0],
+            originalModel = arguments[1],
+            self = this,
+            defer = Ember.RSVP.defer();
+
+        self.createJob = this.createJob;
+
+        this.send('openModal', 'modal-save', {
+          heading: "modals.authenticationLDAP.heading",
+          text:"",
+          type: "password",
+          defer: defer
+        });
+
+        defer.promise.then(function (text) {
+            // make a post call with the given ldap password.
+            var password = text;
+            var pathName = window.location.pathname;
+            var pathNameArray = pathName.split("/");
+            var hiveViewVersion = pathNameArray[3];
+            var hiveViewName = pathNameArray[4];
+            var ldapAuthURL = "/api/v1/views/HIVE/versions/"+ hiveViewVersion + "/instances/" + hiveViewName + "/jobs/auth";
+
+
+            $.ajax({
+                url: ldapAuthURL,
+                dataType: "json",
+                type: 'post',
+                headers: {'X-Requested-With': 'XMLHttpRequest', 'X-Requested-By': 'ambari'},
+                contentType: 'application/json',
+                data: JSON.stringify({ "password" : password}),
+                success: function( data, textStatus, jQxhr ){
+                    console.log( "LDAP done: " + data );
+                    self.createJob (job,originalModel);
+                },
+                error: function( jqXhr, textStatus, errorThrown ){
+                    console.log( "LDAP fail: " + errorThrown );
+                        self.get('notifyService').error( "Wrong Credentials." );
+                }
+            });
+
+          });
+    },
+
     stopCurrentJob: function () {
     stopCurrentJob: function () {
       this.get('jobService').stopJob(this.get('model'));
       this.get('jobService').stopJob(this.get('model'));
     },
     },

+ 1 - 0
contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/modal-save.js

@@ -23,6 +23,7 @@ export default Ember.Controller.extend({
     save: function () {
     save: function () {
       this.send('closeModal');
       this.send('closeModal');
       this.defer.resolve(this.get('text'));
       this.defer.resolve(this.get('text'));
+      this.defer.resolve(this.get('type'));
     },
     },
 
 
     close: function () {
     close: function () {

+ 3 - 0
contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js

@@ -98,6 +98,9 @@ TRANSLATIONS = {
 
 
     changeTitle: {
     changeTitle: {
       heading: 'Rename worksheet'
       heading: 'Rename worksheet'
+    },
+    authenticationLDAP: {
+       heading: 'Enter the LDAP password'
     }
     }
   },
   },
 
 

+ 1 - 0
contrib/views/hive/src/main/resources/ui/hive-web/app/routes/application.js

@@ -39,6 +39,7 @@ export default Ember.Route.extend({
         message: options.message,
         message: options.message,
         heading: options.heading,
         heading: options.heading,
         text: options.text,
         text: options.text,
+        type: options.type || "text",
         defer: options.defer
         defer: options.defer
       });
       });
 
 

+ 1 - 1
contrib/views/hive/src/main/resources/ui/hive-web/app/services/database.js

@@ -224,4 +224,4 @@ export default Ember.Service.extend({
 
 
     return defer.promise;
     return defer.promise;
   }
   }
-});
+});

+ 1 - 1
contrib/views/hive/src/main/resources/ui/hive-web/app/templates/modal-save.hbs

@@ -17,5 +17,5 @@
 }}
 }}
 
 
 {{#modal-widget heading=heading close="close" ok="save"}}
 {{#modal-widget heading=heading close="close" ok="save"}}
-  {{input type="text" class="form-control"  value=text }}
+  {{input type=type class="form-control"  value=text }}
 {{/modal-widget}}
 {{/modal-widget}}

+ 16 - 5
contrib/views/hive/src/test/java/org/apache/ambari/view/hive/BaseHiveTest.java

@@ -58,7 +58,6 @@ public abstract class BaseHiveTest {
   @Before
   @Before
   public void setUp() throws Exception {
   public void setUp() throws Exception {
     handler = createNiceMock(ViewResourceHandler.class);
     handler = createNiceMock(ViewResourceHandler.class);
-    context = createNiceMock(ViewContext.class);
 
 
     properties = new HashMap<String, String>();
     properties = new HashMap<String, String>();
     baseDir = new File(DATA_DIRECTORY)
     baseDir = new File(DATA_DIRECTORY)
@@ -66,19 +65,31 @@ public abstract class BaseHiveTest {
     hiveStorageFile = new File("./target/HiveTest/storage.dat")
     hiveStorageFile = new File("./target/HiveTest/storage.dat")
         .getAbsoluteFile();
         .getAbsoluteFile();
 
 
+    setupDefaultContextProperties(properties);
+    setupProperties(properties, baseDir);
+
+    context = makeContext(properties, "ambari-qa", "MyHive");
+
+    replay(handler, context);
+  }
+
+  public void setupDefaultContextProperties(Map<String, String> properties) {
     properties.put("dataworker.storagePath", hiveStorageFile.toString());
     properties.put("dataworker.storagePath", hiveStorageFile.toString());
     properties.put("scripts.dir", "/tmp/.hiveQueries");
     properties.put("scripts.dir", "/tmp/.hiveQueries");
     properties.put("jobs.dir", "/tmp/.hiveJobs");
     properties.put("jobs.dir", "/tmp/.hiveJobs");
     properties.put("yarn.ats.url", "127.0.0.1:8188");
     properties.put("yarn.ats.url", "127.0.0.1:8188");
     properties.put("yarn.resourcemanager.url", "127.0.0.1:8088");
     properties.put("yarn.resourcemanager.url", "127.0.0.1:8088");
+  }
 
 
+  public ViewContext makeContext(Map<String, String> properties, String username, String instanceName) throws Exception {
+    setupDefaultContextProperties(properties);
     setupProperties(properties, baseDir);
     setupProperties(properties, baseDir);
 
 
+    ViewContext context = createNiceMock(ViewContext.class);
     expect(context.getProperties()).andReturn(properties).anyTimes();
     expect(context.getProperties()).andReturn(properties).anyTimes();
-    expect(context.getUsername()).andReturn("ambari-qa").anyTimes();
-    expect(context.getInstanceName()).andReturn("MyHive").anyTimes();
-
-    replay(handler, context);
+    expect(context.getUsername()).andReturn(username).anyTimes();
+    expect(context.getInstanceName()).andReturn(instanceName).anyTimes();
+    return context;
   }
   }
 
 
   protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
   protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {

+ 63 - 0
contrib/views/hive/src/test/java/org/apache/ambari/view/hive/client/ConnectionTest.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.client;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.HashMap;
+
+import static org.junit.Assert.*;
+
+public class ConnectionTest {
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void testOpenConnection() throws Exception {
+    HashMap<String, String> auth = new HashMap<String, String>();
+    auth.put("auth", "NONE");
+
+    thrown.expect(HiveClientException.class);
+    thrown.expectMessage("Connection refused");
+    new Connection("nonexistent.host.com", 10000, auth, "ambari-qa", null);
+  }
+
+  @Test
+  public void testAskPasswordWithoutPassword() throws Exception {
+    HashMap<String, String> auth = new HashMap<String, String>();
+    auth.put("auth", "NONE");
+    auth.put("password", "${ask_password}");
+
+    thrown.expect(HiveAuthRequiredException.class);
+    new Connection("nonexistent.host.com", 10000, auth, "ambari-qa", null);
+  }
+
+  @Test
+  public void testAskPasswordWithPassword() throws Exception {
+    HashMap<String, String> auth = new HashMap<String, String>();
+    auth.put("auth", "NONE");
+    auth.put("password", "${ask_password}");
+
+    thrown.expect(HiveClientException.class);
+    thrown.expectMessage("Connection refused");
+    new Connection("nonexistent.host.com", 10000, auth, "ambari-qa", "password");
+  }
+}

+ 158 - 0
contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobLDAPServiceTest.java

@@ -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.
+ */
+
+package org.apache.ambari.view.hive.resources.jobs;
+
+import org.apache.ambari.view.hive.BaseHiveTest;
+import org.apache.ambari.view.hive.ServiceTestUtils;
+import org.apache.ambari.view.hive.client.Connection;
+import org.apache.ambari.view.hive.client.HiveAuthRequiredException;
+import org.apache.ambari.view.hive.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.hive.utils.HdfsApiMock;
+import org.apache.ambari.view.utils.UserLocal;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.json.simple.JSONObject;
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import javax.ws.rs.WebApplicationException;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+
+public class JobLDAPServiceTest extends BaseHiveTest {
+  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
+  }
+
+  @Override
+  @After
+  public void tearDown() throws Exception {
+    jobService.getSharedObjectsFactory().clear(HdfsApi.class);
+  }
+
+  @Override
+  protected void setupProperties(Map<String, String> properties, File baseDir) throws Exception {
+    super.setupProperties(properties, baseDir);
+    properties.put("hive.host", "nonexistent.host.com");
+    properties.put("hive.port", "10000");
+
+    properties.put("scripts.dir", "/tmp/.hiveQueries");
+    properties.put("jobs.dir", "/tmp/.hiveJobs");
+  }
+
+  private HdfsApiMock setupHdfsApiMock() throws IOException, InterruptedException, HdfsApiException {
+    HdfsApiMock hdfsApiMock = new HdfsApiMock("select * from Z");
+    HdfsApi hdfsApi = hdfsApiMock.getHdfsApi();
+    jobService.getSharedObjectsFactory().setInstance(HdfsApi.class, hdfsApi);
+    replay(hdfsApi);
+    return hdfsApiMock;
+  }
+
+  @Test
+  public void createJobNoPasswordProvided() throws Exception {
+    UserLocal.dropAllConnections(Connection.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put("hive.auth", "auth=NONE;password=${ask_password}");
+    context = makeContext(properties, "ambari-qa-1", "MyHive");
+    replay(context);
+    jobService = getService(JobService.class, handler, context);
+    setupHdfsApiMock();
+
+    JobService.JobRequest request = new JobService.JobRequest();
+    request.job = new JobImpl();
+    request.job.setForcedContent("Hello world");
+
+    thrown.expect(HiveAuthRequiredException.class);
+    jobService.create(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+  }
+
+  @Test
+  public void createJobNoPasswordRequired() throws Exception {
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put("hive.auth", "auth=NONE");
+    context = makeContext(properties, "ambari-qa-2", "MyHive");
+    replay(context);
+    jobService = getService(JobService.class, handler, context);
+    setupHdfsApiMock();
+
+    JobService.JobRequest request = new JobService.JobRequest();
+    request.job = new JobImpl();
+    request.job.setForcedContent("Hello world");
+
+    thrown.expect(new ExpectedJSONErrorMessage("Connection refused"));
+    jobService.create(request,
+        ServiceTestUtils.getResponseWithLocation(), ServiceTestUtils.getDefaultUriInfo());
+  }
+
+  @Test
+  public void createJobPasswordProvided() throws Exception {
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put("hive.auth", "auth=NONE;password=${ask_password}");
+    context = makeContext(properties, "ambari-qa-3", "MyHive");
+    replay(context);
+    jobService = getService(JobService.class, handler, context);
+    setupHdfsApiMock();
+
+    JobService.JobRequest request = new JobService.JobRequest();
+    request.job = new JobImpl();
+    request.job.setForcedContent("Hello world");
+
+    JobService.AuthRequest authRequest = new JobService.AuthRequest();
+    authRequest.password = "ok";
+
+    thrown.expect(new ExpectedJSONErrorMessage("Connection refused"));
+    jobService.setupPassword(authRequest);
+  }
+
+  private static class ExpectedJSONErrorMessage extends BaseMatcher<WebApplicationException> {
+    private String expectedMessage;
+
+    public ExpectedJSONErrorMessage(String message) {
+      this.expectedMessage = message;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+      description.appendText(this.expectedMessage);
+    }
+
+    @Override
+    public boolean matches(Object o) {
+      JSONObject response = (JSONObject) ((WebApplicationException) o).getResponse().getEntity();
+      String message = (String) response.get("message");
+      return message.contains(expectedMessage);
+    }
+  }
+}

+ 2 - 1
contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/JobServiceTest.java

@@ -20,6 +20,7 @@ package org.apache.ambari.view.hive.resources.jobs;
 
 
 import org.apache.ambari.view.hive.ServiceTestUtils;
 import org.apache.ambari.view.hive.ServiceTestUtils;
 import org.apache.ambari.view.hive.BaseHiveTest;
 import org.apache.ambari.view.hive.BaseHiveTest;
+import org.apache.ambari.view.hive.client.UserLocalConnection;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.JobImpl;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.JobImpl;
 import org.apache.ambari.view.hive.utils.HdfsApiMock;
 import org.apache.ambari.view.hive.utils.HdfsApiMock;
 import org.apache.ambari.view.hive.client.Connection;
 import org.apache.ambari.view.hive.client.Connection;
@@ -71,7 +72,7 @@ public class JobServiceTest extends BaseHiveTest {
 
 
     Connection hiveConnection = configureHiveConnectionMock();
     Connection hiveConnection = configureHiveConnectionMock();
 
 
-    jobService.getSharedObjectsFactory().setInstance(Connection.class, hiveConnection);
+    new UserLocalConnection().set(hiveConnection, context);
     jobService.setAggregator(
     jobService.setAggregator(
         new Aggregator(
         new Aggregator(
             jobService.getResourceManager(),
             jobService.getResourceManager(),

+ 129 - 0
contrib/views/utils/src/main/java/org/apache/ambari/view/utils/UserLocal.java

@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.utils;
+
+import org.apache.ambari.view.ViewContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manages end user specific objects.
+ * Ensures that the instance of specific class is exists only in one instance for
+ * specific user of specific instance.
+ * @param <T> user-local class
+ */
+public class UserLocal<T> {
+  private static Map<Class, Map<String, Object>> viewSingletonObjects = new HashMap<Class, Map<String, Object>>();
+  private final Class<? extends T> tClass;
+
+  public UserLocal(Class<? extends T> tClass) {
+    this.tClass =tClass;
+  }
+
+  /**
+   * Initial value of user-local class. Value can be set either by initialValue() on first get() call,
+   * or directly by calling set() method. Default initial value is null, it can be changed by overriding
+   * this method.
+   * @param context initial value usually based on user properties provided by View Context
+   * @return initial value of user-local variable
+   */
+  protected synchronized T initialValue(ViewContext context) {
+    return null;
+  }
+
+  /**
+   * Returns user-local instance.
+   * If instance of class is not present yet for user, calls initialValue to create it.
+   * @param context View context that provides instance and user names.
+   * @return instance
+   */
+  public T get(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(tClass)) {
+      viewSingletonObjects.put(tClass, new HashMap<String, Object>());
+    }
+
+    Map<String, Object> instances = viewSingletonObjects.get(tClass);
+
+    if (!instances.containsKey(getTagName(context))) {
+      instances.put(getTagName(context), initialValue(context));
+    }
+    return (T) instances.get(getTagName(context));
+  }
+
+  /**
+   * Method for directly setting user-local singleton instances.
+   * @param obj new variable value for current user
+   * @param context ViewContext that provides username and instance name
+   */
+  public void set(T obj, ViewContext context) {
+    if (!viewSingletonObjects.containsKey(tClass)) {
+      viewSingletonObjects.put(tClass, new HashMap<String, Object>());
+    }
+
+    Map<String, Object> instances = viewSingletonObjects.get(tClass);
+    instances.put(getTagName(context), obj);
+  }
+
+  /**
+   * Remove instance if it's already exists.
+   * @param context ViewContext that provides username and instance name
+   */
+  public void remove(ViewContext context) {
+    if (viewSingletonObjects.containsKey(tClass)) {
+      Map<String, Object> instances = viewSingletonObjects.get(tClass);
+      if (instances.containsKey(getTagName(context))) {
+        instances.remove(getTagName(context));
+      }
+    }
+  }
+
+  /**
+   * Returns unique key for Map to store a user-local variable.
+   * @param context ViewContext
+   * @return Unique identifier of pair instance-user.
+   */
+  private String getTagName(ViewContext context) {
+    if (context == null) {
+      return "<null>";
+    }
+    return String.format("%s:%s", context.getInstanceName(), context.getUsername());
+  }
+
+  /**
+   * Method for testing purposes, intended to clear the cached user-local instances.
+   * Method should not normally be called from production code.
+   * @param tClass classname instances of which should be dropped
+   */
+  public static void dropAllConnections(Class tClass) {
+    Map<String, Object> instances = viewSingletonObjects.get(tClass);
+    if (instances != null) {
+      viewSingletonObjects.get(tClass).clear();
+    }
+  }
+
+  /**
+   * Method for testing purposes, intended to clear the cached user-local instances.
+   * Drops all classes of user-local variables.
+   * Method should not normally be called from production code.
+   */
+  public static void dropAllConnections() {
+    viewSingletonObjects.clear();
+  }
+}

+ 7 - 4
contrib/views/hive/src/main/java/org/apache/ambari/view/hive/client/IConnectionFactory.java → contrib/views/utils/src/main/java/org/apache/ambari/view/utils/UserLocalFactory.java

@@ -16,9 +16,12 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
-package org.apache.ambari.view.hive.client;
+package org.apache.ambari.view.utils;
 
 
-
-public interface IConnectionFactory {
-  Connection getHiveConnection();
+/**
+ *
+ * @param <T>
+ */
+public interface UserLocalFactory <T>{
+  T create();
 }
 }

+ 3 - 3
contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ViewUserLocalTest.java

@@ -38,7 +38,7 @@ public class ViewUserLocalTest {
     expect(viewContext2.getUsername()).andReturn("leia").anyTimes();
     expect(viewContext2.getUsername()).andReturn("leia").anyTimes();
     replay(viewContext, viewContext2);
     replay(viewContext, viewContext2);
 
 
-    ViewUserLocal<Object> test = new ViewUserLocal<Object>(Object.class) {
+    UserLocal<Object> test = new UserLocal<Object>(Object.class) {
       @Override
       @Override
       protected synchronized Object initialValue(ViewContext context) {
       protected synchronized Object initialValue(ViewContext context) {
         return new Object();
         return new Object();
@@ -61,7 +61,7 @@ public class ViewUserLocalTest {
     expect(viewContext2.getUsername()).andReturn("luke").anyTimes();
     expect(viewContext2.getUsername()).andReturn("luke").anyTimes();
     replay(viewContext, viewContext2);
     replay(viewContext, viewContext2);
 
 
-    ViewUserLocal<Object> test = new ViewUserLocal<Object>(Object.class) {
+    UserLocal<Object> test = new UserLocal<Object>(Object.class) {
       @Override
       @Override
       protected synchronized Object initialValue(ViewContext context) {
       protected synchronized Object initialValue(ViewContext context) {
         return new Object();
         return new Object();
@@ -84,7 +84,7 @@ public class ViewUserLocalTest {
     expect(viewContext2.getUsername()).andReturn("luke").anyTimes();
     expect(viewContext2.getUsername()).andReturn("luke").anyTimes();
     replay(viewContext, viewContext2);
     replay(viewContext, viewContext2);
 
 
-    ViewUserLocal<Object> test = new ViewUserLocal<Object>(Object.class) {
+    UserLocal<Object> test = new UserLocal<Object>(Object.class) {
       @Override
       @Override
       protected synchronized Object initialValue(ViewContext context) {
       protected synchronized Object initialValue(ViewContext context) {
         return new Object();
         return new Object();