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

amansinha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git

commit ca90229b6deea40282927f8ab5c07715a4e18620
Author: Arina Ielchiieva <arina.yelchiy...@gmail.com>
AuthorDate: Sat May 5 15:32:07 2018 +0300

    DRILL-6272: Refactor dynamic UDFs and function initializer tests to 
generate needed binary and source jars at runtime
    
    close apache/drill#1225
---
 exec/java-exec/pom.xml                             |  48 ++
 .../exec/expr/fn/FunctionInitializerTest.java      |  54 +--
 .../apache/drill/exec/udf/dynamic/JarBuilder.java  |  96 ++++
 .../udf/dynamic}/TestDynamicUDFSupport.java        | 523 ++++++++++-----------
 .../java-exec/src/test/resources/drill-udf/pom.xml |  92 ++++
 .../drill/udf/dynamic/CustomAbsFunction.java       |  63 +++
 .../drill/udf/dynamic/CustomLogFunction.java       |  58 +++
 .../udf/dynamic/CustomLowerDummyFunction.java      |  58 +++
 .../drill/udf/dynamic/CustomLowerFunction.java     |  64 +++
 .../drill/udf/dynamic/CustomLowerFunctionV2.java   |  64 +++
 .../drill/udf/dynamic/CustomUpperFunction.java     |  64 +++
 .../apache/drill/udf/dynamic/LowerFunction.java    |  64 +++
 .../drill-udf/src/main/resources/drill-module.conf |   1 +
 .../test/resources/jars/DrillUDF-1.0-sources.jar   | Bin 1892 -> 0 bytes
 .../src/test/resources/jars/DrillUDF-1.0.jar       | Bin 3146 -> 0 bytes
 .../test/resources/jars/DrillUDF-2.0-sources.jar   | Bin 1891 -> 0 bytes
 .../src/test/resources/jars/DrillUDF-2.0.jar       | Bin 3142 -> 0 bytes
 .../jars/DrillUDF-overloading-1.0-sources.jar      | Bin 3473 -> 0 bytes
 .../resources/jars/DrillUDF-overloading-1.0.jar    | Bin 5779 -> 0 bytes
 .../resources/jars/DrillUDF_Copy-1.0-sources.jar   | Bin 1892 -> 0 bytes
 .../src/test/resources/jars/DrillUDF_Copy-1.0.jar  | Bin 3185 -> 0 bytes
 .../jars/DrillUDF_DupFunc-1.0-sources.jar          | Bin 1888 -> 0 bytes
 .../test/resources/jars/DrillUDF_DupFunc-1.0.jar   | Bin 3201 -> 0 bytes
 .../resources/jars/DrillUDF_Empty-1.0-sources.jar  | Bin 536 -> 0 bytes
 .../src/test/resources/jars/DrillUDF_Empty-1.0.jar | Bin 1863 -> 0 bytes
 .../jars/DrillUDF_NoMarkerFile-1.0-sources.jar     | Bin 1715 -> 0 bytes
 .../resources/jars/DrillUDF_NoMarkerFile-1.0.jar   | Bin 3084 -> 0 bytes
 .../resources/jars/v2/DrillUDF-1.0-sources.jar     | Bin 1899 -> 0 bytes
 .../src/test/resources/jars/v2/DrillUDF-1.0.jar    | Bin 3215 -> 0 bytes
 29 files changed, 948 insertions(+), 301 deletions(-)

diff --git a/exec/java-exec/pom.xml b/exec/java-exec/pom.xml
index cbc3a02..345e240 100644
--- a/exec/java-exec/pom.xml
+++ b/exec/java-exec/pom.xml
@@ -584,6 +584,54 @@
       <artifactId>netty-tcnative</artifactId>
       <classifier>${netty.tcnative.classifier}</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-embedder</artifactId>
+      <version>3.5.3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-compat</artifactId>
+      <version>3.5.3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.aether</groupId>
+      <artifactId>aether-connector-basic</artifactId>
+      <version>1.1.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.aether</groupId>
+      <artifactId>aether-transport-wagon</artifactId>
+      <version>1.1.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http</artifactId>
+      <version>3.0.0</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-provider-api</artifactId>
+      <version>3.0.0</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
 
   <profiles>
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java
 
b/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java
index 7c10bd3..2ecb8a0 100644
--- 
a/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java
+++ 
b/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java
@@ -19,20 +19,20 @@ package org.apache.drill.exec.expr.fn;
 
 import com.google.common.collect.Lists;
 import org.apache.drill.categories.SqlFunctionTest;
-import org.apache.drill.test.TestTools;
+import org.apache.drill.exec.udf.dynamic.JarBuilder;
 import org.apache.drill.exec.util.JarUtil;
 import org.codehaus.janino.Java.CompilationUnit;
 import org.junit.BeforeClass;
+import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
+import org.junit.rules.TemporaryFolder;
 
+import java.io.File;
+import java.io.IOException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -45,25 +45,27 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
 
-@RunWith(MockitoJUnitRunner.class)
 @Category(SqlFunctionTest.class)
 public class FunctionInitializerTest {
 
-  private static final String CLASS_NAME = "com.drill.udf.CustomLowerFunction";
+  @ClassRule
+  public static final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  private static final String CLASS_NAME = 
"org.apache.drill.udf.dynamic.CustomLowerFunction";
   private static URLClassLoader classLoader;
 
   @BeforeClass
   public static void init() throws Exception {
-    Path jars = TestTools.WORKING_PATH
-      .resolve(TestTools.TEST_RESOURCES_REL)
-      .resolve("jars");
-    String binaryName = "DrillUDF-1.0.jar";
-    String sourceName = JarUtil.getSourceName(binaryName);
-    URL[] urls = {jars.resolve(binaryName).toUri().toURL(), 
jars.resolve(sourceName).toUri().toURL()};
+    File buildDirectory = temporaryFolder.getRoot();
+    String binaryName = "drill-custom-lower";
+
+    JarBuilder jarBuilder = new JarBuilder("src/test/resources/drill-udf");
+    String binaryJar = jarBuilder.build(binaryName, 
buildDirectory.getAbsolutePath(), "**/CustomLowerFunction.java", null);
+
+    URL[] urls = {
+      Paths.get(buildDirectory.getPath(), binaryJar).toUri().toURL(),
+      Paths.get(buildDirectory.getPath(), 
JarUtil.getSourceName(binaryJar)).toUri().toURL()};
     classLoader = new URLClassLoader(urls);
   }
 
@@ -94,27 +96,21 @@ public class FunctionInitializerTest {
 
   @Test
   public void testConcurrentFunctionBodyLoad() throws Exception {
-    final FunctionInitializer spyFunctionInitializer = spy(new 
FunctionInitializer(CLASS_NAME, classLoader));
     final AtomicInteger counter = new AtomicInteger();
-
-    doAnswer(new Answer<CompilationUnit>() {
+    final FunctionInitializer functionInitializer = new 
FunctionInitializer(CLASS_NAME, classLoader) {
       @Override
-      public CompilationUnit answer(InvocationOnMock invocation) throws 
Throwable {
+      CompilationUnit convertToCompilationUnit(Class<?> clazz) throws 
IOException {
         counter.incrementAndGet();
-        return (CompilationUnit) invocation.callRealMethod();
+        return super.convertToCompilationUnit(clazz);
       }
-    }).when(spyFunctionInitializer).convertToCompilationUnit(any(Class.class));
+    };
 
     int threadsNumber = 5;
     ExecutorService executor = Executors.newFixedThreadPool(threadsNumber);
 
     try {
-      List<Future<String>> results = 
executor.invokeAll(Collections.nCopies(threadsNumber, new Callable<String>() {
-        @Override
-        public String call() {
-          return spyFunctionInitializer.getMethod("eval");
-        }
-      }));
+      List<Future<String>> results = 
executor.invokeAll(Collections.nCopies(threadsNumber,
+        (Callable<String>) () -> functionInitializer.getMethod("eval")));
 
       final Set<String> uniqueResults = new HashSet<>();
       for (Future<String> result : results) {
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java
 
b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java
new file mode 100644
index 0000000..4861c30
--- /dev/null
+++ 
b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.udf.dynamic;
+
+import org.apache.maven.cli.MavenCli;
+import org.apache.maven.cli.logging.Slf4jLogger;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.logging.BaseLoggerManager;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class JarBuilder {
+
+  private static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(JarBuilder.class);
+  private static final String MAVEN_MULTI_MODULE_PROJECT_DIRECTORY = 
"maven.multiModuleProjectDirectory";
+
+  private final MavenCli cli;
+  private final String projectDirectory;
+
+  public JarBuilder(String projectDirectory) {
+    this.cli = new MavenCli() {
+      @Override
+      protected void customizeContainer(PlexusContainer container) {
+        ((DefaultPlexusContainer) container).setLoggerManager(new 
BaseLoggerManager() {
+          @Override
+          protected org.codehaus.plexus.logging.Logger createLogger(String s) {
+            return new Slf4jLogger(logger);
+          }
+        });
+      }
+    };
+    this.projectDirectory = projectDirectory;
+  }
+
+  /**
+   * Builds jars using embedded maven in provided build directory.
+   * Includes files / resources based given pattern, otherwise using defaults 
provided in pom.xml.
+   * Checks if build exit code is 0, i.e. build was successful.
+   *
+   * @param jarName jar name
+   * @param buildDirectory build directory
+   * @param includeFiles pattern indicating which files should be included
+   * @param includeResources pattern indicating which resources should be 
included
+   *
+   * @return binary jar name with jar extension (my-jar.jar)
+   */
+  public String build(String jarName, String buildDirectory, String 
includeFiles, String includeResources) {
+    String originalPropertyValue = 
System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, projectDirectory);
+    try {
+      List<String> params = new LinkedList<>();
+      params.add("clean");
+      params.add("package");
+      params.add("-DskipTests");
+      // uncomment to build with current Drill version
+      // params.add("-Ddrill.version=" + DrillVersionInfo.getVersion());
+      params.add("-Djar.finalName=" + jarName);
+      params.add("-Dcustom.buildDirectory=" + buildDirectory);
+      if (includeFiles != null) {
+        params.add("-Dinclude.files=" + includeFiles);
+      }
+      if (includeResources != null) {
+        params.add("-Dinclude.resources=" + includeResources);
+      }
+      int result = cli.doMain(params.toArray(new String[params.size()]), 
projectDirectory, System.out, System.err);
+      assertEquals("Build should be successful.", 0, result);
+      return jarName + ".jar";
+    } finally {
+      if (originalPropertyValue != null) {
+        System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, 
originalPropertyValue);
+      } else {
+        System.clearProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY);
+      }
+    }
+  }
+
+}
+
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java 
b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java
similarity index 65%
rename from 
exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java
rename to 
exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java
index 41da123..047026d 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java
+++ 
b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.drill;
+package org.apache.drill.exec.udf.dynamic;
 
 import com.google.common.collect.Lists;
 import org.apache.commons.io.FileUtils;
@@ -26,7 +26,6 @@ import org.apache.drill.categories.SqlFunctionTest;
 import org.apache.drill.common.config.CommonConstants;
 import org.apache.drill.common.config.DrillConfig;
 import org.apache.drill.common.exceptions.UserRemoteException;
-import org.apache.drill.test.TestTools;
 import org.apache.drill.exec.ExecConstants;
 import org.apache.drill.exec.exception.VersionMismatchException;
 import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
@@ -40,16 +39,13 @@ import org.apache.drill.exec.util.JarUtil;
 import org.apache.drill.test.BaseTestQuery;
 import org.apache.drill.test.TestBuilder;
 import org.apache.hadoop.fs.FileSystem;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
+import org.junit.rules.ExpectedException;
 
 import java.io.File;
 import java.io.IOException;
@@ -66,9 +62,10 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyString;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.reset;
@@ -76,23 +73,37 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-@RunWith(MockitoJUnitRunner.class)
 @Category({SlowTest.class, SqlFunctionTest.class})
 public class TestDynamicUDFSupport extends BaseTestQuery {
 
-  private static final Path jars = TestTools.WORKING_PATH
-    .resolve(TestTools.TEST_RESOURCES_REL)
-    .resolve("jars");
-  private static final String default_binary_name = "DrillUDF-1.0.jar";
-  private static final String UDF_SUB_DIR = "udf";
-  private static final String default_source_name = 
JarUtil.getSourceName(default_binary_name);
+  private static final String DEFAULT_JAR_NAME = "drill-custom-lower";
   private static URI fsUri;
   private static File udfDir;
+  private static File jarsDir;
+  private static File buildDirectory;
+  private static JarBuilder jarBuilder;
+  private static String defaultBinaryJar;
+  private static String defaultSourceJar;
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
 
   @BeforeClass
-  public static void setup() throws IOException {
-    udfDir = dirTestWatcher.makeSubDir(Paths.get(UDF_SUB_DIR));
+  public static void buildAndStoreDefaultJars() throws IOException {
+    jarsDir = dirTestWatcher.makeSubDir(Paths.get("jars"));
+    buildDirectory = dirTestWatcher.makeSubDir(Paths.get("drill-udf"));
+
+    jarBuilder = new JarBuilder("src/test/resources/drill-udf");
+    defaultBinaryJar = buildJars(DEFAULT_JAR_NAME, 
"**/CustomLowerFunction.java", null);
+    defaultSourceJar = JarUtil.getSourceName(defaultBinaryJar);
+
+    FileUtils.copyFileToDirectory(new File(buildDirectory, defaultBinaryJar), 
jarsDir);
+    FileUtils.copyFileToDirectory(new File(buildDirectory, defaultSourceJar), 
jarsDir);
+  }
 
+  @Before
+  public void setupNewDrillbit() throws Exception {
+    udfDir = dirTestWatcher.makeSubDir(Paths.get("udf"));
     Properties overrideProps = new Properties();
     overrideProps.setProperty(ExecConstants.UDF_DIRECTORY_ROOT, 
udfDir.getAbsolutePath());
     overrideProps.setProperty(ExecConstants.UDF_DIRECTORY_FS, 
FileSystem.DEFAULT_FS);
@@ -101,29 +112,12 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     fsUri = getLocalFileSystem().getUri();
   }
 
-  @Rule
-  public final TestWatcher clearDirs = new TestWatcher() {
-    @Override
-    protected void succeeded(Description description) {
-      reset();
-    }
-
-    @Override
-    protected void failed(Throwable e, Description description) {
-      reset();
-    }
-
-    private void reset() {
-      try {
-        closeClient();
-        FileUtils.cleanDirectory(udfDir);
-        dirTestWatcher.clear();
-        setup();
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-  };
+  @After
+  public void cleanup() throws Exception {
+    closeClient();
+    FileUtils.cleanDirectory(udfDir);
+    dirTestWatcher.clear();
+  }
 
   @Test
   public void testSyntax() throws Exception {
@@ -143,18 +137,26 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
   }
 
   @Test
-  public void testDisableDynamicSupport() throws Exception {
+  public void testDisableDynamicSupportCreate() throws Exception {
     try {
       test("alter system set `exec.udf.enable_dynamic_support` = false");
-      String[] actions = new String[] {"create", "drop"};
-      String query = "%s function using jar 'jar_name.jar'";
-      for (String action : actions) {
-        try {
-          test(query, action);
-        } catch (UserRemoteException e) {
-          assertThat(e.getMessage(), containsString("Dynamic UDFs support is 
disabled."));
-        }
-      }
+      String query = "create function using jar 'jar_name.jar'";
+      thrown.expect(UserRemoteException.class);
+      thrown.expectMessage(containsString("Dynamic UDFs support is 
disabled."));
+      test(query);
+    } finally {
+      test("alter system reset `exec.udf.enable_dynamic_support`");
+    }
+  }
+
+  @Test
+  public void testDisableDynamicSupportDrop() throws Exception {
+    try {
+      test("alter system set `exec.udf.enable_dynamic_support` = false");
+      String query = "drop function using jar 'jar_name.jar'";
+      thrown.expect(UserRemoteException.class);
+      thrown.expectMessage(containsString("Dynamic UDFs support is 
disabled."));
+      test(query);
     } finally {
       test("alter system reset `exec.udf.enable_dynamic_support`");
     }
@@ -162,13 +164,13 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testAbsentBinaryInStaging() throws Exception {
-    final Path staging = 
hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea());
+    Path staging = 
hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea());
 
     String summary = String.format("File %s does not exist on file system %s",
-        staging.resolve(default_binary_name).toUri().getPath(), fsUri);
+        staging.resolve(defaultBinaryJar).toUri().getPath(), fsUri);
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, summary)
@@ -177,15 +179,14 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testAbsentSourceInStaging() throws Exception {
-    final Path staging = 
hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea());
-
-    copyJar(jars, staging, default_binary_name);
+    Path staging = 
hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea());
+    copyJar(jarsDir.toPath(), staging, defaultBinaryJar);
 
     String summary = String.format("File %s does not exist on file system %s",
-        staging.resolve(default_source_name).toUri().getPath(), fsUri);
+        staging.resolve(defaultSourceJar).toUri().getPath(), fsUri);
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, summary)
@@ -194,32 +195,32 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testJarWithoutMarkerFile() throws Exception {
-    String jarWithNoMarkerFile = "DrillUDF_NoMarkerFile-1.0.jar";
-    copyJarsToStagingArea(jarWithNoMarkerFile, 
JarUtil.getSourceName(jarWithNoMarkerFile));
+    String jarName = "drill-no-marker";
+    String jar = buildAndCopyJarsToStagingArea(jarName, null, "**/dummy.conf");
 
     String summary = "Marker file %s is missing in %s";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", jarWithNoMarkerFile)
+        .sqlQuery("create function using jar '%s'", jar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, String.format(summary,
-            CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME, 
jarWithNoMarkerFile))
+            CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME, jar))
         .go();
   }
 
   @Test
   public void testJarWithoutFunctions() throws Exception {
-    String jarWithNoFunctions = "DrillUDF_Empty-1.0.jar";
-    copyJarsToStagingArea(jarWithNoFunctions, 
JarUtil.getSourceName(jarWithNoFunctions));
+    String jarName = "drill-no-functions";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/CustomLowerDummyFunction.java", null);
 
     String summary = "Jar %s does not contain functions";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", jarWithNoFunctions)
+        .sqlQuery("create function using jar '%s'", jar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(false, String.format(summary, jarWithNoFunctions))
+        .baselineValues(false, String.format(summary, jar))
         .go();
   }
 
@@ -231,10 +232,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
         "[custom_lower(VARCHAR-REQUIRED)]";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(true, String.format(summary, default_binary_name))
+        .baselineValues(true, String.format(summary, defaultBinaryJar))
         .go();
 
     RemoteFunctionRegistry remoteFunctionRegistry = 
getDrillbitContext().getRemoteFunctionRegistry();
@@ -243,79 +244,81 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertFalse("Staging area should be empty", 
fs.listFiles(remoteFunctionRegistry.getStagingArea(), false).hasNext());
     assertFalse("Temporary area should be empty", 
fs.listFiles(remoteFunctionRegistry.getTmpArea(), false).hasNext());
 
-    final Path path = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    Path path = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
 
     assertTrue("Binary should be present in registry area",
-      path.resolve(default_binary_name).toFile().exists());
+      path.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should be present in registry area",
-      path.resolve(default_source_name).toFile().exists());
+      path.resolve(defaultBinaryJar).toFile().exists());
 
     Registry registry = remoteFunctionRegistry.getRegistry(new 
DataChangeVersion());
     assertEquals("Registry should contain one jar", 
registry.getJarList().size(), 1);
-    assertEquals(registry.getJar(0).getName(), default_binary_name);
+    assertEquals(registry.getJar(0).getName(), defaultBinaryJar);
   }
 
   @Test
   public void testDuplicatedJarInRemoteRegistry() throws Exception {
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
     copyDefaultJarsToStagingArea();
 
     String summary = "Jar with %s name has been already registered";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(false, String.format(summary, default_binary_name))
+        .baselineValues(false, String.format(summary, defaultBinaryJar))
         .go();
   }
 
   @Test
   public void testDuplicatedJarInLocalRegistry() throws Exception {
-    copyDefaultJarsToStagingArea();
+    String jarName = "drill-custom-upper";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/CustomUpperFunction.java", null);
 
-    test("create function using jar '%s'", default_binary_name);
-    test("select custom_lower('A') from (values(1))");
+    test("create function using jar '%s'", jar);
+    test("select custom_upper('A') from (values(1))");
 
-    copyDefaultJarsToStagingArea();
+    copyJarsToStagingArea(buildDirectory.toPath(), 
jar,JarUtil.getSourceName(jar));
 
     String summary = "Jar with %s name has been already registered";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", jar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(false, String.format(summary, default_binary_name))
+        .baselineValues(false, String.format(summary, jar))
         .go();
   }
 
   @Test
   public void testDuplicatedFunctionsInRemoteRegistry() throws Exception {
-    String jarWithDuplicate = "DrillUDF_Copy-1.0.jar";
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
-    copyJarsToStagingArea(jarWithDuplicate, 
JarUtil.getSourceName(jarWithDuplicate));
+    test("create function using jar '%s'", defaultBinaryJar);
+
+    String jarName = "drill-custom-lower-copy";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/CustomLowerFunction.java", null);
 
     String summary = "Found duplicated function in %s: 
custom_lower(VARCHAR-REQUIRED)";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", jarWithDuplicate)
+        .sqlQuery("create function using jar '%s'", jar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(false, String.format(summary, default_binary_name))
+        .baselineValues(false, String.format(summary, defaultBinaryJar))
         .go();
   }
 
   @Test
   public void testDuplicatedFunctionsInLocalRegistry() throws Exception {
-    String jarWithDuplicate = "DrillUDF_DupFunc-1.0.jar";
-    copyJarsToStagingArea(jarWithDuplicate, 
JarUtil.getSourceName(jarWithDuplicate));
+    String jarName = "drill-lower";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/LowerFunction.java", null);
 
     String summary = "Found duplicated function in %s: 
lower(VARCHAR-REQUIRED)";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", jarWithDuplicate)
+        .sqlQuery("create function using jar '%s'", jar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, String.format(summary, 
LocalFunctionRegistry.BUILT_IN))
@@ -324,10 +327,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testSuccessfulRegistrationAfterSeveralRetryAttempts() throws 
Exception {
-    final RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
-    final Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
-    final Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
-    final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
+    RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
+    Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
+    Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
 
     copyDefaultJarsToStagingArea();
 
@@ -340,10 +343,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
             "[custom_lower(VARCHAR-REQUIRED)]";
 
     testBuilder()
-            .sqlQuery("create function using jar '%s'", default_binary_name)
+            .sqlQuery("create function using jar '%s'", defaultBinaryJar)
             .unOrdered()
             .baselineColumns("ok", "summary")
-            .baselineValues(true, String.format(summary, default_binary_name))
+            .baselineValues(true, String.format(summary, defaultBinaryJar))
             .go();
 
     verify(remoteFunctionRegistry, times(3))
@@ -353,20 +356,20 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertTrue("Temporary area should be empty", 
ArrayUtils.isEmpty(tmpPath.toFile().listFiles()));
 
     assertTrue("Binary should be present in registry area",
-      registryPath.resolve(default_binary_name).toFile().exists());
+      registryPath.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should be present in registry area",
-      registryPath.resolve(default_source_name).toFile().exists());
+      registryPath.resolve(defaultSourceJar).toFile().exists());
 
     Registry registry = remoteFunctionRegistry.getRegistry(new 
DataChangeVersion());
     assertEquals("Registry should contain one jar", 
registry.getJarList().size(), 1);
-    assertEquals(registry.getJar(0).getName(), default_binary_name);
+    assertEquals(registry.getJar(0).getName(), defaultBinaryJar);
   }
 
   @Test
   public void testSuccessfulUnregistrationAfterSeveralRetryAttempts() throws 
Exception {
     RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
 
     reset(remoteFunctionRegistry);
     doThrow(new VersionMismatchException("Version mismatch detected", 1))
@@ -378,10 +381,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
             "[custom_lower(VARCHAR-REQUIRED)]";
 
     testBuilder()
-            .sqlQuery("drop function using jar '%s'", default_binary_name)
+            .sqlQuery("drop function using jar '%s'", defaultBinaryJar)
             .unOrdered()
             .baselineColumns("ok", "summary")
-            .baselineValues(true, String.format(summary, default_binary_name))
+            .baselineValues(true, String.format(summary, defaultBinaryJar))
             .go();
 
     verify(remoteFunctionRegistry, times(3))
@@ -396,10 +399,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testExceedRetryAttemptsDuringRegistration() throws Exception {
-    final RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
-    final Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
-    final Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
-    final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
+    RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
+    Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
+    Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
 
     copyDefaultJarsToStagingArea();
 
@@ -409,7 +412,7 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     String summary = "Failed to update remote function registry. Exceeded 
retry attempts limit.";
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, summary)
@@ -419,9 +422,9 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
         .updateRegistry(any(Registry.class), any(DataChangeVersion.class));
 
     assertTrue("Binary should be present in staging area",
-            stagingPath.resolve(default_binary_name).toFile().exists());
+            stagingPath.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should be present in staging area",
-            stagingPath.resolve(default_source_name).toFile().exists());
+            stagingPath.resolve(defaultSourceJar).toFile().exists());
 
     assertTrue("Registry area should be empty", 
ArrayUtils.isEmpty(registryPath.toFile().listFiles()));
     assertTrue("Temporary area should be empty", 
ArrayUtils.isEmpty(tmpPath.toFile().listFiles()));
@@ -432,11 +435,11 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testExceedRetryAttemptsDuringUnregistration() throws Exception {
-    final RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
-    final Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
+    Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
 
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
 
     reset(remoteFunctionRegistry);
     doThrow(new VersionMismatchException("Version mismatch detected", 1))
@@ -445,7 +448,7 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     String summary = "Failed to update remote function registry. Exceeded 
retry attempts limit.";
 
     testBuilder()
-        .sqlQuery("drop function using jar '%s'", default_binary_name)
+        .sqlQuery("drop function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, summary)
@@ -455,25 +458,23 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
         .updateRegistry(any(Registry.class), any(DataChangeVersion.class));
 
     assertTrue("Binary should be present in registry area",
-      registryPath.resolve(default_binary_name).toFile().exists());
+      registryPath.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should be present in registry area",
-      registryPath.resolve(default_source_name).toFile().exists());
+      registryPath.resolve(defaultSourceJar).toFile().exists());
 
     Registry registry = remoteFunctionRegistry.getRegistry(new 
DataChangeVersion());
     assertEquals("Registry should contain one jar", 
registry.getJarList().size(), 1);
-    assertEquals(registry.getJar(0).getName(), default_binary_name);
+    assertEquals(registry.getJar(0).getName(), defaultBinaryJar);
   }
 
   @Test
   public void testLazyInit() throws Exception {
-    try {
-      test("select custom_lower('A') from (values(1))");
-    } catch (UserRemoteException e){
-      assertThat(e.getMessage(), containsString("No match found for function 
signature custom_lower(<CHARACTER>)"));
-    }
+    thrown.expect(UserRemoteException.class);
+    thrown.expectMessage(containsString("No match found for function signature 
custom_lower(<CHARACTER>)"));
+    test("select custom_lower('A') from (values(1))");
 
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
     testBuilder()
         .sqlQuery("select custom_lower('A') as res from (values(1))")
         .unOrdered()
@@ -485,21 +486,19 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
       getDrillbitContext().getFunctionImplementationRegistry(), "localUdfDir", 
true));
 
     assertTrue("Binary should exist in local udf directory",
-      localUdfDirPath.resolve(default_binary_name).toFile().exists());
+      localUdfDirPath.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should exist in local udf directory",
-      localUdfDirPath.resolve(default_source_name).toFile().exists());
+      localUdfDirPath.resolve(defaultSourceJar).toFile().exists());
   }
 
   @Test
   public void testLazyInitWhenDynamicUdfSupportIsDisabled() throws Exception {
-    try {
-      test("select custom_lower('A') from (values(1))");
-    } catch (UserRemoteException e){
-      assertThat(e.getMessage(), containsString("No match found for function 
signature custom_lower(<CHARACTER>)"));
-    }
+    thrown.expect(UserRemoteException.class);
+    thrown.expectMessage(containsString("No match found for function signature 
custom_lower(<CHARACTER>)"));
+    test("select custom_lower('A') from (values(1))");
 
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
 
     try {
       testBuilder()
@@ -516,9 +515,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testOverloadedFunctionPlanningStage() throws Exception {
-    String jarName = "DrillUDF-overloading-1.0.jar";
-    copyJarsToStagingArea(jarName, JarUtil.getSourceName(jarName));
-    test("create function using jar '%s'", jarName);
+    String jarName = "drill-custom-abs";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/CustomAbsFunction.java", null);
+
+    test("create function using jar '%s'", jar);
 
     testBuilder()
         .sqlQuery("select abs('A', 'A') as res from (values(1))")
@@ -530,9 +530,10 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
   @Test
   public void testOverloadedFunctionExecutionStage() throws Exception {
-    String jarName = "DrillUDF-overloading-1.0.jar";
-    copyJarsToStagingArea(jarName, JarUtil.getSourceName(jarName));
-    test("create function using jar '%s'", jarName);
+    String jarName = "drill-custom-log";
+    String jar = buildAndCopyJarsToStagingArea(jarName, 
"**/CustomLogFunction.java", null);
+
+    test("create function using jar '%s'", jar);
 
     testBuilder()
         .sqlQuery("select log('A') as res from (values(1))")
@@ -545,67 +546,65 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
   @Test
   public void testDropFunction() throws Exception {
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
     test("select custom_lower('A') from (values(1))");
 
     Path localUdfDirPath = 
hadoopToJavaPath((org.apache.hadoop.fs.Path)FieldUtils.readField(
         getDrillbitContext().getFunctionImplementationRegistry(), 
"localUdfDir", true));
 
     assertTrue("Binary should exist in local udf directory",
-      localUdfDirPath.resolve(default_binary_name).toFile().exists());
+      localUdfDirPath.resolve(defaultBinaryJar).toFile().exists());
     assertTrue("Source should exist in local udf directory",
-      localUdfDirPath.resolve(default_source_name).toFile().exists());
+      localUdfDirPath.resolve(defaultSourceJar).toFile().exists());
 
     String summary = "The following UDFs in jar %s have been unregistered:\n" +
         "[custom_lower(VARCHAR-REQUIRED)]";
 
     testBuilder()
-        .sqlQuery("drop function using jar '%s'", default_binary_name)
+        .sqlQuery("drop function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(true, String.format(summary, default_binary_name))
+        .baselineValues(true, String.format(summary, defaultBinaryJar))
         .go();
 
-    try {
-      test("select custom_lower('A') from (values(1))");
-    } catch (UserRemoteException e){
-      assertThat(e.getMessage(), containsString("No match found for function 
signature custom_lower(<CHARACTER>)"));
-    }
+    thrown.expect(UserRemoteException.class);
+    thrown.expectMessage(containsString("No match found for function signature 
custom_lower(<CHARACTER>)"));
+    test("select custom_lower('A') from (values(1))");
 
-    final RemoteFunctionRegistry remoteFunctionRegistry = 
getDrillbitContext().getRemoteFunctionRegistry();
-    final Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    RemoteFunctionRegistry remoteFunctionRegistry = 
getDrillbitContext().getRemoteFunctionRegistry();
+    Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
 
     assertEquals("Remote registry should be empty",
         remoteFunctionRegistry.getRegistry(new 
DataChangeVersion()).getJarList().size(), 0);
 
     assertFalse("Binary should not be present in registry area",
-      registryPath.resolve(default_binary_name).toFile().exists());
+      registryPath.resolve(defaultBinaryJar).toFile().exists());
     assertFalse("Source should not be present in registry area",
-      registryPath.resolve(default_source_name).toFile().exists());
+      registryPath.resolve(defaultSourceJar).toFile().exists());
 
     assertFalse("Binary should not be present in local udf directory",
-      localUdfDirPath.resolve(default_binary_name).toFile().exists());
+      localUdfDirPath.resolve(defaultBinaryJar).toFile().exists());
     assertFalse("Source should not be present in local udf directory",
-      localUdfDirPath.resolve(default_source_name).toFile().exists());
+      localUdfDirPath.resolve(defaultSourceJar).toFile().exists());
   }
 
   @Test
   public void testReRegisterTheSameJarWithDifferentContent() throws Exception {
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
     testBuilder()
         .sqlQuery("select custom_lower('A') as res from (values(1))")
         .unOrdered()
         .baselineColumns("res")
         .baselineValues("a")
         .go();
-    test("drop function using jar '%s'", default_binary_name);
+    test("drop function using jar '%s'", defaultBinaryJar);
 
     Thread.sleep(1000);
 
-    Path src = jars.resolve("v2");
-    copyJarsToStagingArea(src, default_binary_name, default_source_name);
-    test("create function using jar '%s'", default_binary_name);
+    buildAndCopyJarsToStagingArea(DEFAULT_JAR_NAME, 
"**/CustomLowerFunctionV2.java", null);
+
+    test("create function using jar '%s'", defaultBinaryJar);
     testBuilder()
         .sqlQuery("select custom_lower('A') as res from (values(1))")
         .unOrdered()
@@ -619,36 +618,33 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     String summary = "Jar %s is not registered in remote registry";
 
     testBuilder()
-        .sqlQuery("drop function using jar '%s'", default_binary_name)
+        .sqlQuery("drop function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
-        .baselineValues(false, String.format(summary, default_binary_name))
+        .baselineValues(false, String.format(summary, defaultBinaryJar))
         .go();
   }
 
   @Test
   public void testRegistrationFailDuringRegistryUpdate() throws Exception {
-    final RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
-    final Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
-    final Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
-    final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
+    RemoteFunctionRegistry remoteFunctionRegistry = 
spyRemoteFunctionRegistry();
+    Path registryPath = 
hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea());
+    Path stagingPath = 
hadoopToJavaPath(remoteFunctionRegistry.getStagingArea());
+    Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea());
 
     final String errorMessage = "Failure during remote registry update.";
-    doAnswer(new Answer<Void>() {
-      @Override
-      public Void answer(InvocationOnMock invocation) throws Throwable {
-        assertTrue("Binary should be present in registry area",
-            registryPath.resolve(default_binary_name).toFile().exists());
-        assertTrue("Source should be present in registry area",
-            registryPath.resolve(default_source_name).toFile().exists());
-        throw new RuntimeException(errorMessage);
-      }
+    doAnswer(invocation -> {
+      assertTrue("Binary should be present in registry area",
+          registryPath.resolve(defaultBinaryJar).toFile().exists());
+      assertTrue("Source should be present in registry area",
+          registryPath.resolve(defaultSourceJar).toFile().exists());
+      throw new RuntimeException(errorMessage);
     }).when(remoteFunctionRegistry).updateRegistry(any(Registry.class), 
any(DataChangeVersion.class));
 
     copyDefaultJarsToStagingArea();
 
     testBuilder()
-        .sqlQuery("create function using jar '%s'", default_binary_name)
+        .sqlQuery("create function using jar '%s'", defaultBinaryJar)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(false, errorMessage)
@@ -657,8 +653,8 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertTrue("Registry area should be empty", 
ArrayUtils.isEmpty(registryPath.toFile().listFiles()));
     assertTrue("Temporary area should be empty", 
ArrayUtils.isEmpty(tmpPath.toFile().listFiles()));
 
-    assertTrue("Binary should be present in staging area", 
stagingPath.resolve(default_binary_name).toFile().exists());
-    assertTrue("Source should be present in staging area", 
stagingPath.resolve(default_source_name).toFile().exists());
+    assertTrue("Binary should be present in staging area", 
stagingPath.resolve(defaultBinaryJar).toFile().exists());
+    assertTrue("Source should be present in staging area", 
stagingPath.resolve(defaultSourceJar).toFile().exists());
   }
 
   @Test
@@ -668,21 +664,18 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     final CountDownLatch latch1 = new CountDownLatch(1);
     final CountDownLatch latch2 = new CountDownLatch(1);
 
-    doAnswer(new Answer<String>() {
-      @Override
-      public String answer(InvocationOnMock invocation) throws Throwable {
-        String result = (String) invocation.callRealMethod();
-        latch2.countDown();
-        latch1.await();
-        return result;
-      }
+    doAnswer(invocation -> {
+      String result = (String) invocation.callRealMethod();
+      latch2.countDown();
+      latch1.await();
+      return result;
     })
         .doCallRealMethod()
         .doCallRealMethod()
         .when(remoteFunctionRegistry).addToJars(anyString(), 
any(RemoteFunctionRegistry.Action.class));
 
 
-    final String query = String.format("create function using jar '%s'", 
default_binary_name);
+    final String query = String.format("create function using jar '%s'", 
defaultBinaryJar);
 
     Thread thread = new Thread(new SimpleQueryRunner(query));
     thread.start();
@@ -695,14 +688,14 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
           .sqlQuery(query)
           .unOrdered()
           .baselineColumns("ok", "summary")
-          .baselineValues(false, String.format(summary, default_binary_name))
+          .baselineValues(false, String.format(summary, defaultBinaryJar))
           .go();
 
       testBuilder()
-          .sqlQuery("drop function using jar '%s'", default_binary_name)
+          .sqlQuery("drop function using jar '%s'", defaultBinaryJar)
           .unOrdered()
           .baselineColumns("ok", "summary")
-          .baselineValues(false, String.format(summary, default_binary_name))
+          .baselineValues(false, String.format(summary, defaultBinaryJar))
           .go();
 
     } finally {
@@ -719,51 +712,45 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     final CountDownLatch latch2 = new CountDownLatch(1);
     final CountDownLatch latch3 = new CountDownLatch(1);
 
-    doAnswer(new Answer<Void>() {
-      @Override
-      public Void answer(InvocationOnMock invocation) throws Throwable {
-        latch3.countDown();
-        latch1.await();
-        invocation.callRealMethod();
-        latch2.countDown();
-        return null;
-      }
-    }).doAnswer(new Answer<Void>() {
-      @Override
-      public Void answer(InvocationOnMock invocation) throws Throwable {
-        latch1.countDown();
-        latch2.await();
-        invocation.callRealMethod();
-        return null;
-      }
+    doAnswer(invocation -> {
+      latch3.countDown();
+      latch1.await();
+      invocation.callRealMethod();
+      latch2.countDown();
+      return null;
+    }).doAnswer(invocation -> {
+      latch1.countDown();
+      latch2.await();
+      invocation.callRealMethod();
+      return null;
     })
         .when(remoteFunctionRegistry).updateRegistry(any(Registry.class), 
any(DataChangeVersion.class));
 
+    final String jar1 = defaultBinaryJar;
+    copyDefaultJarsToStagingArea();
 
-    final String jarName1 = default_binary_name;
-    final String jarName2 = "DrillUDF_Copy-1.0.jar";
-    final String query = "create function using jar '%s'";
+    final String copyJarName = "drill-custom-lower-copy";
+    final String jar2 = buildAndCopyJarsToStagingArea(copyJarName, 
"**/CustomLowerFunction.java", null);
 
-    copyDefaultJarsToStagingArea();
-    copyJarsToStagingArea(jarName2, JarUtil.getSourceName(jarName2));
+    final String query = "create function using jar '%s'";
 
     Thread thread1 = new Thread(new TestBuilderRunner(
         testBuilder()
-        .sqlQuery(query, jarName1)
+        .sqlQuery(query, jar1)
         .unOrdered()
         .baselineColumns("ok", "summary")
         .baselineValues(true,
             String.format("The following UDFs in jar %s have been 
registered:\n" +
-            "[custom_lower(VARCHAR-REQUIRED)]", jarName1))
+            "[custom_lower(VARCHAR-REQUIRED)]", jar1))
     ));
 
     Thread thread2 = new Thread(new TestBuilderRunner(
         testBuilder()
-            .sqlQuery(query, jarName2)
+            .sqlQuery(query, jar2)
             .unOrdered()
             .baselineColumns("ok", "summary")
             .baselineValues(false,
-                String.format("Found duplicated function in %s: 
custom_lower(VARCHAR-REQUIRED)", jarName1))
+                String.format("Found duplicated function in %s: 
custom_lower(VARCHAR-REQUIRED)", jar1))
     ));
 
     thread1.start();
@@ -778,7 +765,7 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertEquals("Remote registry version should match", 1, 
version.getVersion());
     List<Jar> jarList = registry.getJarList();
     assertEquals("Only one jar should be registered", 1, jarList.size());
-    assertEquals("Jar name should match", jarName1, jarList.get(0).getName());
+    assertEquals("Jar name should match", jar1, jarList.get(0).getName());
 
     verify(remoteFunctionRegistry, 
times(2)).updateRegistry(any(Registry.class), any(DataChangeVersion.class));
   }
@@ -789,43 +776,40 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     final CountDownLatch latch1 = new CountDownLatch(1);
     final CountDownLatch latch2 = new CountDownLatch(2);
 
-    doAnswer(new Answer<Void>() {
-      @Override
-      public Void answer(InvocationOnMock invocation) throws Throwable {
-        latch2.countDown();
-        latch1.await();
-        invocation.callRealMethod();
-        return null;
-      }
+    doAnswer(invocation -> {
+      latch2.countDown();
+      latch1.await();
+      invocation.callRealMethod();
+      return null;
     })
         .when(remoteFunctionRegistry).updateRegistry(any(Registry.class), 
any(DataChangeVersion.class));
 
-    final String jarName1 = default_binary_name;
-    final String jarName2 = "DrillUDF-2.0.jar";
-    final String query = "create function using jar '%s'";
-
+    final String jar1 = defaultBinaryJar;
     copyDefaultJarsToStagingArea();
-    copyJarsToStagingArea(jarName2, JarUtil.getSourceName(jarName2));
 
+    final String upperJarName = "drill-custom-upper";
+    final String jar2 = buildAndCopyJarsToStagingArea(upperJarName, 
"**/CustomUpperFunction.java", null);
+
+    final String query = "create function using jar '%s'";
 
     Thread thread1 = new Thread(new TestBuilderRunner(
         testBuilder()
-            .sqlQuery(query, jarName1)
+            .sqlQuery(query, jar1)
             .unOrdered()
             .baselineColumns("ok", "summary")
             .baselineValues(true,
                 String.format("The following UDFs in jar %s have been 
registered:\n" +
-                    "[custom_lower(VARCHAR-REQUIRED)]", jarName1))
+                    "[custom_lower(VARCHAR-REQUIRED)]", jar1))
     ));
 
 
     Thread thread2 = new Thread(new TestBuilderRunner(
         testBuilder()
-            .sqlQuery(query, jarName2)
+            .sqlQuery(query, jar2)
             .unOrdered()
             .baselineColumns("ok", "summary")
             .baselineValues(true, String.format("The following UDFs in jar %s 
have been registered:\n" +
-                "[custom_upper(VARCHAR-REQUIRED)]", jarName2))
+                "[custom_upper(VARCHAR-REQUIRED)]", jar2))
     ));
 
     thread1.start();
@@ -842,7 +826,7 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertEquals("Remote registry version should match", 2, 
version.getVersion());
 
     List<Jar> actualJars = registry.getJarList();
-    List<String> expectedJars = Lists.newArrayList(jarName1, jarName2);
+    List<String> expectedJars = Lists.newArrayList(jar1, jar2);
 
     assertEquals("Only one jar should be registered", 2, actualJars.size());
     for (Jar jar : actualJars) {
@@ -856,32 +840,26 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
   public void testLazyInitConcurrent() throws Exception {
     FunctionImplementationRegistry functionImplementationRegistry = 
spyFunctionImplementationRegistry();
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
+    test("create function using jar '%s'", defaultBinaryJar);
 
     final CountDownLatch latch1 = new CountDownLatch(1);
     final CountDownLatch latch2 = new CountDownLatch(1);
 
     final String query = "select custom_lower('A') from (values(1))";
 
-    doAnswer(new Answer<Boolean>() {
-      @Override
-      public Boolean answer(InvocationOnMock invocation) throws Throwable {
-        latch1.await();
-        boolean result = (boolean) invocation.callRealMethod();
-        assertTrue("syncWithRemoteRegistry() should return true", result);
-        latch2.countDown();
-        return true;
-      }
+    doAnswer(invocation -> {
+      latch1.await();
+      boolean result = (boolean) invocation.callRealMethod();
+      assertTrue("syncWithRemoteRegistry() should return true", result);
+      latch2.countDown();
+      return true;
     })
-        .doAnswer(new Answer() {
-          @Override
-          public Boolean answer(InvocationOnMock invocation) throws Throwable {
-            latch1.countDown();
-            latch2.await();
-            boolean result = (boolean) invocation.callRealMethod();
-            assertTrue("syncWithRemoteRegistry() should return true", result);
-            return true;
-          }
+        .doAnswer(invocation -> {
+          latch1.countDown();
+          latch2.await();
+          boolean result = (boolean) invocation.callRealMethod();
+          assertTrue("syncWithRemoteRegistry() should return true", result);
+          return true;
         })
         
.when(functionImplementationRegistry).syncWithRemoteRegistry(anyLong());
 
@@ -905,23 +883,17 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
   public void testLazyInitNoReload() throws Exception {
     FunctionImplementationRegistry functionImplementationRegistry = 
spyFunctionImplementationRegistry();
     copyDefaultJarsToStagingArea();
-    test("create function using jar '%s'", default_binary_name);
-
-    doAnswer(new Answer<Boolean>() {
-      @Override
-      public Boolean answer(InvocationOnMock invocation) throws Throwable {
-        boolean result = (boolean) invocation.callRealMethod();
-        assertTrue("syncWithRemoteRegistry() should return true", result);
-        return true;
-      }
+    test("create function using jar '%s'", defaultBinaryJar);
+
+    doAnswer(invocation -> {
+      boolean result = (boolean) invocation.callRealMethod();
+      assertTrue("syncWithRemoteRegistry() should return true", result);
+      return true;
     })
-        .doAnswer(new Answer() {
-          @Override
-          public Boolean answer(InvocationOnMock invocation) throws Throwable {
-            boolean result = (boolean) invocation.callRealMethod();
-            assertFalse("syncWithRemoteRegistry() should return false", 
result);
-            return false;
-          }
+        .doAnswer(invocation -> {
+          boolean result = (boolean) invocation.callRealMethod();
+          assertFalse("syncWithRemoteRegistry() should return false", result);
+          return false;
         })
         
.when(functionImplementationRegistry).syncWithRemoteRegistry(anyLong());
 
@@ -929,6 +901,7 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
 
     try {
       test("select unknown_lower('A') from (values(1))");
+      fail();
     } catch (UserRemoteException e){
       assertThat(e.getMessage(), containsString("No match found for function 
signature unknown_lower(<CHARACTER>)"));
     }
@@ -939,12 +912,18 @@ public class TestDynamicUDFSupport extends BaseTestQuery {
     assertEquals("Sync function registry version should match", 1L, 
localFunctionRegistry.getVersion());
   }
 
+  private static String buildJars(String jarName, String includeFiles, String 
includeResources) {
+    return jarBuilder.build(jarName, buildDirectory.getAbsolutePath(), 
includeFiles, includeResources);
+  }
+
   private void copyDefaultJarsToStagingArea() throws IOException {
-    copyJarsToStagingArea(jars, default_binary_name, default_source_name);
+    copyJarsToStagingArea(jarsDir.toPath(), defaultBinaryJar, 
defaultSourceJar);
   }
 
-  private void copyJarsToStagingArea(String binaryName, String sourceName) 
throws IOException  {
-    copyJarsToStagingArea(jars, binaryName, sourceName);
+  private String buildAndCopyJarsToStagingArea(String jarName, String 
includeFiles, String includeResources) throws IOException {
+    String binaryJar = buildJars(jarName, includeFiles, includeResources);
+    copyJarsToStagingArea(buildDirectory.toPath(), binaryJar, 
JarUtil.getSourceName(binaryJar));
+    return binaryJar;
   }
 
   private void copyJarsToStagingArea(Path src, String binaryName, String 
sourceName) throws IOException {
diff --git a/exec/java-exec/src/test/resources/drill-udf/pom.xml 
b/exec/java-exec/src/test/resources/drill-udf/pom.xml
new file mode 100644
index 0000000..7361845
--- /dev/null
+++ b/exec/java-exec/src/test/resources/drill-udf/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.drill.udf</groupId>
+  <artifactId>drill-udf</artifactId>
+  <version>1.0</version>
+
+  <properties>
+    <jar.finalName>${project.name}</jar.finalName>
+    <custom.buildDirectory>${project.basedir}/target</custom.buildDirectory>
+    <drill.version>1.13.0</drill.version>
+    <include.files>**/*.java</include.files>
+    <include.resources>**/*.conf</include.resources>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.drill.exec</groupId>
+      <artifactId>drill-java-exec</artifactId>
+      <version>${drill.version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <directory>${custom.buildDirectory}</directory>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <includes>
+          <include>${include.resources}</include>
+        </includes>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.1</version>
+        <configuration>
+          <includes>
+            <include>${include.files}</include>
+          </includes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.4</version>
+        <configuration>
+          <finalName>${jar.finalName}</finalName>
+          <includes>
+            <include>${include.files}</include>
+          </includes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+
+</project>
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.java
new file mode 100644
index 0000000..9bdcffb
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.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.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="abs",
+    scope= FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class CustomAbsFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input1;
+
+  @Param
+  VarCharHolder input2;
+
+  @Output
+  VarCharHolder out;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+
+  }
+
+  public void eval() {
+    String inputString1 = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input1.start,
 input1.end, input1.buffer);
+    String inputString2 = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input2.start,
 input2.end, input2.buffer);
+    String outputValue = String.format("ABS was overloaded. Input: %s, %s", 
inputString1, inputString2);
+
+    out.buffer = buffer;
+    out.start = 0;
+    out.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java
new file mode 100644
index 0000000..fa49a35
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="log",
+    scope= FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class CustomLogFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder out;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+
+  }
+
+  public void eval() {
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+    String outputValue = "LOG was overloaded. Input: " + inputString;
+
+    out.buffer = buffer;
+    out.start = 0;
+    out.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java
new file mode 100644
index 0000000..1e401d1
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+public class CustomLowerDummyFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder output;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+  }
+
+  public void eval() {
+
+    // get value
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+
+    // convert to lower case
+    String outputValue = inputString.toLowerCase();
+
+    // put the output value into output buffer
+    output.buffer = buffer;
+    output.start = 0;
+    output.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java
new file mode 100644
index 0000000..f868be3
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="custom_lower",
+    scope = FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class CustomLowerFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder output;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+  }
+
+  public void eval() {
+
+    // get value
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+
+    // convert to lower case
+    String outputValue = inputString.toLowerCase();
+
+    // put the output value into output buffer
+    output.buffer = buffer;
+    output.start = 0;
+    output.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java
new file mode 100644
index 0000000..e564d7f
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="custom_lower",
+    scope = FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class CustomLowerFunctionV2 implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder output;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+  }
+
+  public void eval() {
+
+    // get value
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+
+    // convert to lower case
+    String outputValue = inputString.toLowerCase() + "_v2";
+
+    // put the output value into output buffer
+    output.buffer = buffer;
+    output.start = 0;
+    output.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java
new file mode 100644
index 0000000..9ac473b
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="custom_upper",
+    scope = FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class CustomUpperFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder output;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+  }
+
+  public void eval() {
+
+    // get value
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+
+    // convert to upper case
+    String outputValue = inputString.toUpperCase();
+
+    // put the output value into output buffer
+    output.buffer = buffer;
+    output.start = 0;
+    output.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java
new file mode 100644
index 0000000..0d5d149
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.udf.dynamic;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.inject.Inject;
+
+@FunctionTemplate(
+    name="lower",
+    scope = FunctionTemplate.FunctionScope.SIMPLE,
+    nulls = FunctionTemplate.NullHandling.NULL_IF_NULL
+)
+public class LowerFunction implements DrillSimpleFunc {
+
+  @Param
+  VarCharHolder input;
+
+  @Output
+  VarCharHolder output;
+
+  @Inject
+  DrillBuf buffer;
+
+  public void setup() {
+  }
+
+  public void eval() {
+
+    // get value
+    String inputString = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start,
 input.end, input.buffer);
+
+    // convert to lower case
+    String outputValue = inputString.toLowerCase();
+
+    // put the output value into output buffer
+    output.buffer = buffer;
+    output.start = 0;
+    output.end = outputValue.getBytes().length;
+    buffer.setBytes(0, outputValue.getBytes());
+
+  }
+}
+
diff --git 
a/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf
 
b/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf
new file mode 100644
index 0000000..0b2948a
--- /dev/null
+++ 
b/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf
@@ -0,0 +1 @@
+drill.classpath.scanning.packages += "org.apache.drill.udf.dynamic"
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar
deleted file mode 100644
index b5965c9..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar 
and /dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar
deleted file mode 100644
index 7cd2eeb..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar
deleted file mode 100644
index 1c8308c..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar 
and /dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar
deleted file mode 100644
index 3522c1e..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar and 
/dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar
deleted file mode 100644
index f6b250e..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar 
and /dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar
deleted file mode 100644
index 4b5ef8b..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar and 
/dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar
deleted file mode 100644
index fa449e2..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar
deleted file mode 100644
index 8945fe7..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar and 
/dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar
deleted file mode 100644
index b19ade6..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar
deleted file mode 100644
index 56a649c..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar 
and /dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar
deleted file mode 100644
index 2a82dc9..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar
deleted file mode 100644
index 11ed28b..0000000
Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar 
and /dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar
deleted file mode 100644
index dbc97dd..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar 
and /dev/null differ
diff --git 
a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar 
b/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar
deleted file mode 100644
index cba65da..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar 
b/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar
deleted file mode 100644
index 583b1c4..0000000
Binary files 
a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar and 
/dev/null differ
diff --git a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar 
b/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar
deleted file mode 100644
index 42df4a4..0000000
Binary files a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar and 
/dev/null differ

-- 
To stop receiving notification emails like this one, please contact
amansi...@apache.org.

Reply via email to