diff --git common/src/java/org/apache/hadoop/hive/conf/HiveConf.java common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index 0b4dad9..242e7f6 100644 --- common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -749,6 +749,7 @@ HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS("hive.server2.custom.authentication.class", null), HIVE_SERVER2_ENABLE_DOAS("hive.server2.enable.doAs", true), HIVE_SERVER2_TABLE_TYPE_MAPPING("hive.server2.table.type.mapping", "HIVE"), + HIVE_SERVER2_SESSION_HOOK("hive.server2.session.hook", ""), HIVE_CONF_RESTRICTED_LIST("hive.conf.restricted.list", null), diff --git ql/src/java/org/apache/hadoop/hive/ql/Driver.java ql/src/java/org/apache/hadoop/hive/ql/Driver.java index 3312b3b..8e3a675 100644 --- ql/src/java/org/apache/hadoop/hive/ql/Driver.java +++ ql/src/java/org/apache/hadoop/hive/ql/Driver.java @@ -40,8 +40,8 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hive.common.JavaUtils; import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; import org.apache.hadoop.hive.metastore.MetaStoreUtils; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.metastore.api.Schema; @@ -58,6 +58,7 @@ import org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext; import org.apache.hadoop.hive.ql.hooks.Hook; import org.apache.hadoop.hive.ql.hooks.HookContext; +import org.apache.hadoop.hive.ql.hooks.HookUtils; import org.apache.hadoop.hive.ql.hooks.PostExecute; import org.apache.hadoop.hive.ql.hooks.PreExecute; import org.apache.hadoop.hive.ql.hooks.ReadEntity; @@ -82,8 +83,8 @@ import org.apache.hadoop.hive.ql.metadata.formatting.MetaDataFormatter; import org.apache.hadoop.hive.ql.optimizer.ppr.PartitionPruner; import org.apache.hadoop.hive.ql.parse.ASTNode; -import org.apache.hadoop.hive.ql.parse.AbstractSemanticAnalyzerHook; import org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer; +import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHook; import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContext; import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContextImpl; import org.apache.hadoop.hive.ql.parse.ImportSemanticAnalyzer; @@ -423,20 +424,20 @@ public int compile(String command, boolean resetTaskIds) { tree = ParseUtils.findRootNonNullToken(tree); BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(conf, tree); - List saHooks = + List saHooks = getHooks(HiveConf.ConfVars.SEMANTIC_ANALYZER_HOOK, - AbstractSemanticAnalyzerHook.class); + HiveSemanticAnalyzerHook.class); // Do semantic analysis and plan generation if (saHooks != null) { HiveSemanticAnalyzerHookContext hookCtx = new HiveSemanticAnalyzerHookContextImpl(); hookCtx.setConf(conf); - for (AbstractSemanticAnalyzerHook hook : saHooks) { + for (HiveSemanticAnalyzerHook hook : saHooks) { tree = hook.preAnalyze(hookCtx, tree); } sem.analyze(tree, ctx); hookCtx.update(sem); - for (AbstractSemanticAnalyzerHook hook : saHooks) { + for (HiveSemanticAnalyzerHook hook : saHooks) { hook.postAnalyze(hookCtx, sem.getRootTasks()); } } else { @@ -949,7 +950,8 @@ private CommandProcessorResponse runInternal(String command) throws CommandNeedR // Get all the driver run hooks and pre-execute them. List driverRunHooks; try { - driverRunHooks = getHooks(HiveConf.ConfVars.HIVE_DRIVER_RUN_HOOKS, HiveDriverRunHook.class); + driverRunHooks = getHooks(HiveConf.ConfVars.HIVE_DRIVER_RUN_HOOKS, + HiveDriverRunHook.class); for (HiveDriverRunHook driverRunHook : driverRunHooks) { driverRunHook.preDriverRun(hookContext); } @@ -1075,8 +1077,7 @@ private boolean validateConfVariables() { } /** - * Returns the hooks specified in a configuration variable. The hooks are returned in a list in - * the order they were specified in the configuration variable. + * Returns the hooks specified in a configuration variable. * * @param hookConfVar The configuration variable specifying a comma separated list of the hook * class names. @@ -1085,34 +1086,14 @@ private boolean validateConfVariables() { * they are listed in the value of hookConfVar * @throws Exception */ - private List getHooks(HiveConf.ConfVars hookConfVar, Class clazz) - throws Exception { - - List hooks = new ArrayList(); - String csHooks = conf.getVar(hookConfVar); - if (csHooks == null) { - return hooks; - } - - csHooks = csHooks.trim(); - if (csHooks.equals("")) { - return hooks; - } - - String[] hookClasses = csHooks.split(","); - - for (String hookClass : hookClasses) { - try { - T hook = - (T) Class.forName(hookClass.trim(), true, JavaUtils.getClassLoader()).newInstance(); - hooks.add(hook); - } catch (ClassNotFoundException e) { - console.printError(hookConfVar.varname + " Class not found:" + e.getMessage()); - throw e; - } + private List getHooks(ConfVars hookConfVar, + Class clazz) throws Exception { + try { + return HookUtils.getHooks(conf, hookConfVar, clazz); + } catch (ClassNotFoundException e) { + console.printError(hookConfVar.varname + " Class not found:" + e.getMessage()); + throw e; } - - return hooks; } public int execute() throws CommandNeedRetryException { diff --git ql/src/java/org/apache/hadoop/hive/ql/hooks/HookUtils.java ql/src/java/org/apache/hadoop/hive/ql/hooks/HookUtils.java new file mode 100644 index 0000000..dbcd7bb --- /dev/null +++ ql/src/java/org/apache/hadoop/hive/ql/hooks/HookUtils.java @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hive.ql.hooks; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.hadoop.hive.common.JavaUtils; +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; + +public class HookUtils { + /** + * Returns the hooks specified in a configuration variable. The hooks are returned + * in a list in the order they were specified in the configuration variable. + * + * @param conf Configuration object + * @param hookConfVar The configuration variable specifying a comma separated list + * of the hook class names. + * @param clazz The super type of the hooks. + * @return A list of the hooks cast as the type specified in clazz, + * in the order they are listed in the value of hookConfVar + * @throws ClassNotFoundException + * @throws IllegalAccessException + * @throws InstantiationException + */ + public static List getHooks(HiveConf conf, + ConfVars hookConfVar, Class clazz) + throws InstantiationException, IllegalAccessException, ClassNotFoundException { + List hooks = new ArrayList(); + String csHooks = conf.getVar(hookConfVar); + if (csHooks == null) { + return hooks; + } + + csHooks = csHooks.trim(); + if (csHooks.equals("")) { + return hooks; + } + + String[] hookClasses = csHooks.split(","); + for (String hookClass : hookClasses) { + T hook = (T) Class.forName(hookClass.trim(), true, + JavaUtils.getClassLoader()).newInstance(); + hooks.add(hook); + } + + return hooks; + } + +} diff --git service/src/java/org/apache/hive/service/cli/session/HiveSessionHook.java service/src/java/org/apache/hive/service/cli/session/HiveSessionHook.java new file mode 100644 index 0000000..5063317 --- /dev/null +++ service/src/java/org/apache/hive/service/cli/session/HiveSessionHook.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hive.service.cli.session; + +import org.apache.hadoop.hive.ql.hooks.Hook; +import org.apache.hive.service.cli.HiveSQLException; + +/** + * + * HiveSessionHook. + * HiveServer2 session level Hook interface. The run method is executed + * when session manager starts a new session + * + */ +public interface HiveSessionHook extends Hook { + + /** + * @param sessionHookContext + * @throws HiveSQLException + */ + public void run(HiveSessionHookContext sessionHookContext) throws HiveSQLException; +} diff --git service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContext.java service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContext.java new file mode 100644 index 0000000..156c814 --- /dev/null +++ service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContext.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hive.service.cli.session; + +import org.apache.hadoop.hive.conf.HiveConf; +/** + * HiveSessionHookContext. + * Interface passed to the HiveServer2 session hook execution. This enables + * the hook implementation to accesss session config, user and session handle + */ +public interface HiveSessionHookContext { + + /** + * Retrieve session conf + * @return + */ + public HiveConf getSessionConf(); + + /** + * The get the username starting the session + * @return + */ + public String getSessionUser(); + + /** + * Retrieve handle for the session + * @return + */ + public String getSessionHandle(); +} diff --git service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContextImpl.java service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContextImpl.java new file mode 100644 index 0000000..1ee4ac8 --- /dev/null +++ service/src/java/org/apache/hive/service/cli/session/HiveSessionHookContextImpl.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hive.service.cli.session; + +import org.apache.hadoop.hive.conf.HiveConf; + +/** + * + * HiveSessionHookContextImpl. + * Session hook context implementation which is created by session manager + * and passed to hook invocation. + */ +public class HiveSessionHookContextImpl implements HiveSessionHookContext { + + private final HiveSession hiveSession; + + HiveSessionHookContextImpl(HiveSession hiveSession) { + this.hiveSession = hiveSession; + } + + @Override + public HiveConf getSessionConf() { + return hiveSession.getHiveConf(); + } + + + @Override + public String getSessionUser() { + return hiveSession.getUserName(); + } + + @Override + public String getSessionHandle() { + return hiveSession.getSessionHandle().toString(); + } +} diff --git service/src/java/org/apache/hive/service/cli/session/SessionManager.java service/src/java/org/apache/hive/service/cli/session/SessionManager.java index 3bb6807..214b54c 100644 --- service/src/java/org/apache/hive/service/cli/session/SessionManager.java +++ service/src/java/org/apache/hive/service/cli/session/SessionManager.java @@ -19,9 +19,11 @@ package org.apache.hive.service.cli.session; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.ql.hooks.HookUtils; import org.apache.hive.service.CompositeService; import org.apache.hive.service.cli.HiveSQLException; import org.apache.hive.service.cli.SessionHandle; @@ -90,6 +92,11 @@ public SessionHandle openSession(String username, String password, Map sessionHooks = HookUtils.getHooks(hiveConf, + HiveConf.ConfVars.HIVE_SERVER2_SESSION_HOOK, HiveSessionHook.class); + for (HiveSessionHook sessionHook : sessionHooks) { + sessionHook.run(new HiveSessionHookContextImpl(session)); + } + } } diff --git service/src/test/org/apache/hive/service/cli/session/TestSessionHooks.java service/src/test/org/apache/hive/service/cli/session/TestSessionHooks.java new file mode 100644 index 0000000..b10c619 --- /dev/null +++ service/src/test/org/apache/hive/service/cli/session/TestSessionHooks.java @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hive.service.cli.session; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hive.service.cli.HiveSQLException; +import org.apache.hive.service.cli.SessionHandle; +import org.apache.hive.service.cli.thrift.EmbeddedThriftCLIService; +import org.apache.hive.service.cli.thrift.ThriftCLIServiceClient; +import org.junit.Before; +import org.junit.Test; + +public class TestSessionHooks extends TestCase { + + public static final String SESSION_USER_NAME = "user1"; + private EmbeddedThriftCLIService service; + private ThriftCLIServiceClient client; + + public static class SessionHookTest implements HiveSessionHook { + + public static AtomicInteger runCount = new AtomicInteger(0); + + @Override + public void run(HiveSessionHookContext sessionHookContext) throws HiveSQLException { + Assert.assertEquals(sessionHookContext.getSessionUser(), SESSION_USER_NAME); + String sessionHook = sessionHookContext.getSessionConf(). + getVar(ConfVars.HIVE_SERVER2_SESSION_HOOK); + Assert.assertTrue(sessionHook.contains(this.getClass().getName())); + Assert.assertEquals(0, runCount.getAndIncrement()); + } + } + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + System.setProperty(ConfVars.HIVE_SERVER2_SESSION_HOOK.varname, + TestSessionHooks.SessionHookTest.class.getName()); + service = new EmbeddedThriftCLIService(); + client = new ThriftCLIServiceClient(service); + } + + @Test + public void testSessionHook () throws Exception { + // create session, test if the hook got fired by checking the expected property + SessionHandle sessionHandle = client.openSession(SESSION_USER_NAME, "foobar", + Collections.emptyMap()); + Assert.assertEquals(1, SessionHookTest.runCount.get()); + client.closeSession(sessionHandle); + } +}