trafodion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hzel...@apache.org
Subject [1/2] incubator-trafodion git commit: TRAFODION-2534 CLASSPATH for Java UDRs
Date Mon, 03 Apr 2017 16:41:55 GMT
Repository: incubator-trafodion
Updated Branches:
  refs/heads/master 1bd6c78d2 -> 0c88f432d


TRAFODION-2534 CLASSPATH for Java UDRs

Two changes in the custom Java class loader used for UDRs.

First, the class loader now adds any jar files stored in
$TRAF_HOME/udr/public/external_libs to its CLASSPATH.
The choice of this directory is anticipating work on
isolated UDFs, see TRAFODION-2561.

Second, the custom class loader LmClassLoader now uses
java.net.URLClassLoader to do most of the work. This allows
us to delete a lot of code in this file. When this class
was first written, many years ago, the URLClassLoader was
probably not yet available.

Finally, with the new class loader, the JDBC predefined
UDF can also be simplified.


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

Branch: refs/heads/master
Commit: da1b7b8f8d6b0ed3d8b40cd43406a9e1a717d776
Parents: 8691d78
Author: Hans Zeller <hzeller@apache.org>
Authored: Thu Mar 30 01:04:51 2017 +0000
Committer: Hans Zeller <hzeller@apache.org>
Committed: Thu Mar 30 01:52:21 2017 +0000

----------------------------------------------------------------------
 core/sql/langman/LmLangManagerJava.cpp          | 112 +------
 core/sql/langman/LmLangManagerJava.h            |   8 -
 .../org/trafodion/sql/udr/LmClassLoader.java    | 327 ++++---------------
 .../java/org/trafodion/sql/udr/LmUtility.java   | 136 +++++++-
 .../org/trafodion/sql/udr/predef/JDBCUDR.java   |  56 ++--
 5 files changed, 226 insertions(+), 413 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/da1b7b8f/core/sql/langman/LmLangManagerJava.cpp
----------------------------------------------------------------------
diff --git a/core/sql/langman/LmLangManagerJava.cpp b/core/sql/langman/LmLangManagerJava.cpp
index 38713a9..6724821 100644
--- a/core/sql/langman/LmLangManagerJava.cpp
+++ b/core/sql/langman/LmLangManagerJava.cpp
@@ -114,8 +114,6 @@ if (result == LM_PARAM_OVERFLOW)			\
 // Class LmLanguageManagerJava
 //
 //////////////////////////////////////////////////////////////////////
-char* LmLanguageManagerJava::classPath_ = NULL;
-char* LmLanguageManagerJava::sysClassPath_ = NULL;
 ComUInt32 LmLanguageManagerJava::maxLMJava_ = 0;
 ComUInt32 LmLanguageManagerJava::numLMJava_ = 0;
 
@@ -205,8 +203,8 @@ void LmLanguageManagerJava::initialize(LmResult &result,
   // contain garbage values. Some of the error handling routines
   // called by this constructor will use a method ID if it has a
   // non-NULL value.
-  loadClassId_ = loaderSizeId_ = addCpURLsId_ = 
-  removeCpURLsId_ = verifyMethodId_ = createCLId_ = setCPId_ =
+  loadClassId_ =
+  verifyMethodId_ = createCLId_ =
   utilityInitId_ = classCacheSizeId_ = classCacheEnforceId_ =
   systemGetPropId_ = systemSetPropId_ = systemClearPropId_ = 
   bigdecCtorId_ = bigdecStrId_ = bigdecUnscaleId_ = 
@@ -240,9 +238,6 @@ void LmLanguageManagerJava::initialize(LmResult &result,
 
   ++numLMJava_;
  
-  if (numLMJava_ == 1)
-    setJavaClassPath();
-
   if (numLMJava_ > maxLMJava_)
   {
     *diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
@@ -281,8 +276,6 @@ void LmLanguageManagerJava::initialize(LmResult &result,
 #ifdef LM_DEBUG
     actualJvmOptions->display();
     LM_DEBUG0("");
-    LM_DEBUG1("classPath_ is %s", classPath_ ? classPath_ : "NULL");
-    LM_DEBUG1("sysClassPath_ is %s", sysClassPath_ ? sysClassPath_ : "NULL");
     const char *jrehome = getenv("JREHOME");
     LM_DEBUG1("JREHOME is %s", jrehome ? jrehome : "NULL");
     LM_DEBUG1("commandLineMode_ is %s",
@@ -418,8 +411,6 @@ void LmLanguageManagerJava::initialize(LmResult &result,
   // Asserts, just to check we don't have NULL pointers
   LM_ASSERT(LmSqlJVM != NULL);
   LM_ASSERT(jniEnv_ != NULL);
-  LM_ASSERT(sysClassPath_ != NULL);
-
 
   // record the constructing thread's ID.
   threadId_ = threadId();
@@ -541,15 +532,8 @@ void LmLanguageManagerJava::initialize(LmResult &result,
     loaderClass_ = jc;
     loadClassId_ = jni->GetMethodID(jc, "loadClass",
                                     "(Ljava/lang/String;)Ljava/lang/Class;");
-    setCPId_ = jni->GetStaticMethodID(jc, "setClassPath",
-                                      "(Ljava/lang/String;)V");
-    addCpURLsId_ = jni->GetMethodID(jc, "addCpURLs", "()V");
-    removeCpURLsId_ = jni->GetMethodID(jc, "removeCpURLs", "()V");
-    loaderSizeId_ = jni->GetMethodID(jc, "size", "()I");
-
-    if (jni->ExceptionOccurred() || loadClassId_  == NULL || 
-        removeCpURLsId_ == NULL  || setCPId_      == NULL ||
-        loaderSizeId_   == NULL  || addCpURLsId_  == NULL)
+
+    if (jni->ExceptionOccurred() || loadClassId_  == NULL)
     {
       result = exceptionReporter_->insertDiags(diagsArea_,
                                                -LME_JVM_SYS_CLASS_ERROR,
@@ -563,27 +547,6 @@ void LmLanguageManagerJava::initialize(LmResult &result,
     return;
   }
 
-  // Set classPath for LmClassLoader(seen by all instances of ClassLoader)
-  if (classPath_ != NULL)
-  {
-    jstring jCP = jni->NewStringUTF(classPath_);
-    result = exceptionReporter_->checkNewObjectExceptions(jCP, diagsArea_);
-    if(result == LM_ERR)
-      return;
-
-    jni->CallStaticVoidMethod((jclass)loaderClass_, (jmethodID)setCPId_, jCP);
-    jni->DeleteLocalRef(jCP);
-
-    if (jni->ExceptionOccurred())
-    {
-      result = exceptionReporter_->insertDiags(diagsArea_,
-                                               -LME_INTERNAL_ERROR,
-                                               ": Could not set search path "
-                                               "in ClassLoader.");
-      return;
-    }
-  }
-
   jc = (jclass) jni->FindClass("org/trafodion/sql/udr/LmCharsetCoder");
   if (jc)
   {
@@ -1472,12 +1435,6 @@ LmLanguageManagerJava::~LmLanguageManagerJava()
   // Adjust the LMJ counter.
   --numLMJava_;
 
-  if (numLMJava_ == 0)
-  {
-    NADELETEBASIC(sysClassPath_, collHeap());
-    NADELETEBASIC(classPath_, collHeap());
-  }
-
   if (userName_)
     NADELETEBASIC(userName_, collHeap());
 
@@ -2230,13 +2187,7 @@ LmHandle LmLanguageManagerJava::loadContainer(
   if(midChk == LM_ERR)
     return NULL;
 
-  //
   // Call the ClassLoader's loadClass() method to get the container.
-  // Before that we need to remove ClassPath from ClassLoader's search
-  // list so that the class will be loaded only from external path.
-  // After calling loadClass(), we add ClassPath again.
-  //
-  jni->CallVoidMethod((jobject)extLoader, (jmethodID)removeCpURLsId_);
   jobj = jni->CallObjectMethod((jobject)extLoader,
                                (jmethodID)loadClassId_,
                                jstr);
@@ -2250,8 +2201,8 @@ LmHandle LmLanguageManagerJava::loadContainer(
     jni->DeleteLocalRef(jobj);
 
     // Call the LmClassLoader's size method to get its current capacity.
-    *containerSize =
-      jni->CallIntMethod((jobject)extLoader, (jmethodID)loaderSizeId_);
+    *containerSize = 100; // currently not implemented,
+                          // could add an interface to verifyClassIsInFile
   }
   else
   {
@@ -2263,9 +2214,6 @@ LmHandle LmLanguageManagerJava::loadContainer(
                                     externalPath);
   }
 
-  // Add the CLASSPATH to the search list of the ClassLoader
-  jni->CallVoidMethod((jobject)extLoader, (jmethodID)addCpURLsId_);
-
   return container;
 }
 
@@ -3674,54 +3622,6 @@ LmResult LmLanguageManagerJava::startService(ComDiagsArea *da)
   }
 }
 
-void LmLanguageManagerJava::setJavaClassPath()
-{
-  ComUInt32 totLen = 0;
-
-  char *ntJars = NULL;
-  char installdir[LMJ_NT_FILE_PATH_LEN];
-  Lng32 resultlength = 0;
-  const char *ntLmJar = "/export/lib/mxlangman.jar";
-  const char *ntTrafJar = "/export/lib/trafodion-UDR-0.7.0.jar";
-  const char *ntJdbcT4Jar = "/export/lib/jdbcT2.jar";
-
-  char *root = getenv("TRAF_HOME");
-  LM_ASSERT(root != NULL);
-  resultlength = strlen(root) + 1;
-  LM_ASSERT(resultlength < LMJ_NT_FILE_PATH_LEN);
-  strcpy(installdir, root);
-  ntJars = new (collHeap())
-    char[3*resultlength + str_len(ntTrafJar) + str_len(ntLmJar) + str_len(ntJdbcT4Jar) +
3];
-  sprintf(ntJars, "%s%s:%s%s:%s%s", installdir, ntLmJar, installdir, ntJdbcT4Jar, installdir,
ntTrafJar);
-
-
-  char *jExt = NULL;
-
-  if (jExt && jExt[0])
-  {
-    totLen = str_len(jExt) + str_len(ntJars);
-    sysClassPath_ = new (collHeap()) char[totLen + 2];
-
-    sprintf(sysClassPath_, "%s:%s", jExt, ntJars);
-    NADELETEBASIC(ntJars, collHeap());
-    ntJars = NULL;
-  }
-  else
-  {
-    sysClassPath_ = ntJars;
-  }
-
-  // Now get CLASSPATH if it's set.
-  char *envClassPath = getenv("CLASSPATH");
-  if (envClassPath && envClassPath[0])
-  {
-    classPath_ = new (collHeap()) char[str_len(envClassPath) + 1];
-    sprintf(classPath_, "%s", envClassPath);
-  }
-
-  return;
-}
-
 /* threadId(): Returns the current thread's ID. OS-dependent.
  */
 ComSInt32 LmLanguageManagerJava::threadId()

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/da1b7b8f/core/sql/langman/LmLangManagerJava.h
----------------------------------------------------------------------
diff --git a/core/sql/langman/LmLangManagerJava.h b/core/sql/langman/LmLangManagerJava.h
index 2e11113..6ef2c6f 100644
--- a/core/sql/langman/LmLangManagerJava.h
+++ b/core/sql/langman/LmLangManagerJava.h
@@ -329,15 +329,11 @@ private:
 
   LmResult startService(ComDiagsArea *da);
 
-  void setJavaClassPath();
-
   ComSInt32 threadId();
 
   void processJavaOptions(const LmJavaOptions &userOptions,
                           LmJavaOptions &jvmOptions);
 
-  static char *sysClassPath_;       // JVM's class path.
-  static char *classPath_;          // class path used by ClassLoader.
   LmContainerManager *contManager_; // LMJ's CM.
   LmHandle jniEnv_;                 // JNI handle. 
   static ComUInt32 maxLMJava_;      // Max LMJs per process.
@@ -378,14 +374,10 @@ private:
 
   LmHandle loaderClass_;         // LmClassLoader
   LmHandle loadClassId_;         // loadClass
-  LmHandle loaderSizeId_;        // size
-  LmHandle addCpURLsId_;	 // addCpURLs
-  LmHandle removeCpURLsId_;	 // removeCpURLs
 
   LmHandle utilityClass_;        // LmUtility
   LmHandle verifyMethodId_;      // verifyMethodSignature
   LmHandle createCLId_;          // createClassLoader
-  LmHandle setCPId_;		 // setClassPath
   LmHandle utilityInitId_;       // init method
   LmHandle classCacheSizeId_;    // static int classCacheSizeKB_
   LmHandle classCacheEnforceId_; // static int classCacheEnforceLimit_

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/da1b7b8f/core/sql/src/main/java/org/trafodion/sql/udr/LmClassLoader.java
----------------------------------------------------------------------
diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/LmClassLoader.java b/core/sql/src/main/java/org/trafodion/sql/udr/LmClassLoader.java
index 939f643..04ba64a 100644
--- a/core/sql/src/main/java/org/trafodion/sql/udr/LmClassLoader.java
+++ b/core/sql/src/main/java/org/trafodion/sql/udr/LmClassLoader.java
@@ -44,176 +44,83 @@ import java.util.jar.JarEntry;
 
 import java.net.URL;
 import java.net.URLConnection;
+import java.net.URLClassLoader;
 
 import java.security.AccessController;
 import java.security.CodeSource;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.security.SecureClassLoader;
 
 /**
- * LmClassLoader is an extension of SecureClassLoader.
- * This class is responsible for loading the classes from its search path.
- * Search Path includes external path(the directory specified in 'external path'
- * clause of 'create procedure' statement) and CLASSPATH env variable. This class
- * always checks external path first before checking CLASSPATH.
- *
- * CLASSPATH can be removed from the search path by calling removeCpURLs() 
- * and added by addCpURLs(). This facility is provided to have the main class
- * (the one specified in 'external name' clause of 'create procedure') loaded
- * only from 'external path'. Typically, applications call removeCpURLs() before
- * loading main class and call addCpURLs() after loading the class.
+ * LmClassLoader is an extension of URLClassLoader which in turn is
+ * derived from SecureClassLoader.  This class is responsible for
+ * loading the classes from its search path.  Since Java class loaders
+ * try the parent class loader first, the search path of this class
+ * loader tries the following, in sequence:
+ * - the CLASSPATH as defined in the environment variable
+ * - the name of the container for the UDR
+ * - jar files in $TRAF_HOME/udr/public/external_libs, in alphabetical
+ *   order
  *
  **/
-public class LmClassLoader extends SecureClassLoader
+public class LmClassLoader extends URLClassLoader
 {
-  private int debug_; 	      // Debug flag.
-  private String path_;       // The external path managed by the loader.
-  private int size_;          // Total size in bytes for loaded classes.
-  private boolean chkCpURLs_; // flag to check CLASSPATH URLs.
-  private URL urlCS_;         // The URL (used to get the CodeSource)
-			      // corresponding to the loaded class. 
   private final static boolean DEBUG = false; // static DEBUG
 
-  static private Vector<String> cpURLs_ = null;    // vector of URLs used by all instances
-				           // of this Class. Created from CLASSPATH
 
   /**
-   * Creates a new instance for given external path.
+   * Creates a new instance for a given set of URLs.
    * And adds external path to the search path.
    * @param extPath    external path this instance is responsible for
    * @param debug      debug flag
    *
    **/
-  public LmClassLoader(String extPath, int debug)
-  {
-    super();
-    debug_ = debug;
-    if (DEBUG)
-      System.out.println("LmClassLoader::LmClassLoader extPath=" + extPath);
-    path_ = extPath;
-    size_ = 0;
-    chkCpURLs_ = true;
-  }
-
-  /**
-   * Sets the classpath.
-   * This classpath is seen by all the LmClassLoader instances.
-   * @param  classPath  CLASSPATH to set
-   *
-   **/
-  public static void setClassPath(String classPath)
+  public LmClassLoader(URL[] urls)
   {
-    cpURLs_ = createURLVector(classPath);
+      super(urls);
   }
 
-  /**
-   * Creates a vector of URLs from given path.
-   * Here URL refers to a String type (not java.net.URL type) representing dir or
-   * jar file. 'path' is a set of elements(dir or jar file names) separated by
-   * ':' or ';' depending on the platform.
-   *
-   * @param   path set of directories or jar file names separated by ':' or ';'
-   * @return  a Vector of String type(dirs and jars)
-   *
-   **/
-  private static Vector<String> createURLVector(String path)
+  String getContainerPath()
   {
-    Vector<String> v = new Vector<String>();
-    if (path == null)
-    {
-      return v;
-    }
-
-    StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
-
-    while (st.hasMoreTokens())
-    {
-      String url = st.nextToken();
-      v.addElement(url);
-    }
-
-    return v;
+      // The first URL points to the container. Get the path of that URL
+      return getURLs()[0].getPath();
   }
 
   /**
-   * Accessor method to get the size of all the loaded classes by this
-   * ClassLoader.
-   * @return size of all the loaded classes.
+   * Finds the class in the path specified in the LmClassLoader constructor
+   * without looking in other files. This does not actually load the class.
+   * @param  name of the class name to be loaded
+   * @return the size of the path file
+   * @throws  ClassNotFoundException
    *
    **/
-  public int size()
-  {
-    return size_;
-  }
 
-  /**
-   * Adds CLASSPATH URLs to the search path of this ClassLoader instance.
-   *
-   **/
-  public void addCpURLs()
-  {
-    chkCpURLs_ = true;
-    return;
-  }
-
-  /**
-   * Removes CLASSPATH URLs from the search list of this ClassLoader instance.
-   * CLASSPATH won't be checked for ClassLoading until addCpURLs() is called.
-   *
-   **/
-  public void removeCpURLs()
-  {
-    chkCpURLs_ = false;
-    return;
-  }
-
-  /**
-   * Finds the class in the search path of this ClassLoader instance.
-   * Search path includes external path and CLASSPATH(if it is added to
-   * the search path) in that order.
-   * This method overrides the one in baseclass.
-   * @param  name class name to be loaded
-   * @return the resulting Class object
-   *
-   **/
-
-  protected Class findClass(String name)
+  long verifyClassIsInFile(String resourceName)
     throws ClassNotFoundException
   {
     // Change the package qualified name to directory structure name
-    final String dname = name.replace('.', '/') + ".class";
+    final String dname = resourceName.replace('.', '/') + ".class";
 
     try
     {
-      byte[] b = (byte[]) 
-      AccessController.doPrivileged(new PrivilegedExceptionAction()
-      {
-	 public Object run() throws Exception 
-	 {
-	   return loadClassData(dname);
-	 }
-      });
-
-      if (b != null) 
-      {
-        size_ += b.length;
-
-        // Get the CodeSource for the url. urlCS_  was set in
-        // loadClassData. urlCS_ and will be deallocated before returning.
-        CodeSource cs = new CodeSource(urlCS_, (java.security.cert.Certificate[])null);
-
-        Class c = defineClass(name, b, 0, b.length, cs);
-        urlCS_ = null;
-        return c;
-      } 
+        File f =
+          AccessController.doPrivileged(new PrivilegedExceptionAction<File>()
+              {
+                  public File run() throws Exception
+                  {
+                      return findResourceInternal(dname);
+                  }
+              });
+
+      if (f != null)
+          return f.length();
       else 
       {
-        throw new ClassNotFoundException(name);
+        throw new ClassNotFoundException(resourceName);
       }
     } catch (PrivilegedActionException e)
         {
-          throw new ClassNotFoundException(name, e.getException());
+          throw new ClassNotFoundException(resourceName, e.getException());
         }
       catch (ClassNotFoundException e)
 	{
@@ -221,162 +128,40 @@ public class LmClassLoader extends SecureClassLoader
 	}
       catch (Exception e)
         {
-	  throw new ClassNotFoundException(name, e);
+	  throw new ClassNotFoundException(resourceName, e);
         }
   }
 
   /**
-   * Reads the bytes of the given class from external path or CLASSPATH(if included
-   * in search path).
-   * @param  name class name to read
-   * @return bytes of the class,
-   *         null if the class is not found
-   **/
-  private byte[] loadClassData(String name)
-  throws Exception
-  {
-    URL u = findResourceInternal(name, chkCpURLs_);
-
-    if (u == null)
-      return null;
-
-    urlCS_ = u;
-
-    return readFromURLSource(u);
-  }
-
-  /**
-   * Reads bytes from the given URL. 
-   * @param   url URL to read from
-   * @return  bytes of the file
-   *          null if the protocol is not 'file' or 'jar'
-   **/
-  private byte[] readFromURLSource(URL url)
-    throws Exception
-  {
-    BufferedInputStream bis = null;
-
-    try
-    {
-      String prot = url.getProtocol();
-      if (!prot.equals("file") && !prot.equals("jar"))
-        return null;
-
-      URLConnection connection = url.openConnection();
-      connection.setDefaultUseCaches(false); // Do not use caches
-
-      bis = new BufferedInputStream(connection.getInputStream());
-      int size = connection.getContentLength();
-
-      return readFromStream(bis, size);
-    } catch(Exception e)
-        {
-          throw e;
-        }
-      finally
-        {
-          try
-          {
-            bis.close();
-          } catch (Exception e)
-              { }
-        }
-  }
-
-  /**
-   * Reads specified number of bytes from the given stream.
-   * Caller needs to open and close the  stream.
-   * @param bis  Buffered input stream to read from
-   * @param size number of bytes to read
-   * @return byte array
-   *
-   **/
-  private byte[] readFromStream(BufferedInputStream bis, int size)
-  throws Exception
-  {
-    byte buf[] = new byte[size];
-    int bytesRead = 0, offset = 0;
-
-    while ((size - offset) > 0)
-    {
-      bytesRead = bis.read(buf, offset, size - offset);
-      if (bytesRead == -1)
-        break;
-      offset += bytesRead;
-    }
-
-    return buf;
-  }
-
-  /**
-   * Finds the resource with the given name.
-   * Checks search path (external path and CLASSPATH) for the resource.
-   * This method overrides the one in baseclass.
-   * @param  name  the resource name
-   * @return a URL for reading the resource,
-   *         or null if the resource could not be found
-   **/
-  protected URL findResource(String name)
-  {
-    return findResourceInternal(name, true);
-  }
-
-  /**
    * Finds the resource with the given name.
-   * Checks search path (external path and CLASSPATH) for the resource.
+   * This method only checks the given container, not the CLASSPATH or
+   * other jars.
    * @param  name  the resource name
-   * @return a URL for reading the resource,
-   *         or null if the resource could not be found
+   * @return a File object for the file containing the resource or null if not found
    **/
-  private URL findResourceInternal(String name, boolean searchClassPath)
+  public File findResourceInternal(String name) throws Exception
   {
-    int searchSize = 0;
-    if (searchClassPath == true && cpURLs_ != null)
-      searchSize = cpURLs_.size();
-
-    for (int i=-1; i<searchSize; i++)
-    {
-      String element;
+    String path = getContainerPath();
+    File f = new File(path);
 
-      if (i == -1)
-        element = path_;
-      else
-        element = (String)cpURLs_.elementAt(i);
+    if (DEBUG)
+      System.out.println("LmClassLoader::findResourceInternal trying " + path);
 
-      try
+    if (f.isFile())
       {
-        if (DEBUG)
-          System.out.println("LmClassLoader::findResourceInternal trying " + element);
-        File f = new File(element);
-        if (f.isFile())
-        {
-          JarFile jf = new JarFile(element);
-          JarEntry je = jf.getJarEntry(name);
-          jf.close();
-          if (je != null)
+        JarFile jf = new JarFile(path);
+        JarEntry je = jf.getJarEntry(name);
+        jf.close();
+        if (je != null)
           {
             if (DEBUG)
-              System.out.println("LmClassLoader::findResourceInternal returning jar:file:"
+ element + "!/" + name);
-            return (new URL("jar:file:" + element + "!/" + name));
+              System.out.println("LmClassLoader::findResourceInternal returning jar:file:"
+ path + "!/" + name);
+            return f;
           }
-        }
-        else
-        {
-          String filename = element + "/" + name;
-          if (DEBUG)
-            System.out.println("LmClassLoader::findResourceInternal trying " + filename);
-          File file = new File(filename);
-          if (file.exists() == true)
-          {
-            if (DEBUG)
-              System.out.println("LmClassLoader::findResourceInternal returning file:" +
filename);
-            return (new URL("file:" + filename));
-          }
-        }
-      } catch (Exception e) { }
-
-    }
+      }
 
+    if (DEBUG)
+        System.out.println("LmClassLoader::findResourceInternal did not find resource " +
name + "in container " + path);
     return null;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/da1b7b8f/core/sql/src/main/java/org/trafodion/sql/udr/LmUtility.java
----------------------------------------------------------------------
diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/LmUtility.java b/core/sql/src/main/java/org/trafodion/sql/udr/LmUtility.java
index d321b74..441c88d 100644
--- a/core/sql/src/main/java/org/trafodion/sql/udr/LmUtility.java
+++ b/core/sql/src/main/java/org/trafodion/sql/udr/LmUtility.java
@@ -38,6 +38,9 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.io.*;
+import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.sql.ResultSet;
 import java.lang.reflect.Field;
 import java.lang.Class;
@@ -886,21 +889,37 @@ public class LmUtility {
       try
       {  
         lmcl = createClassLoader(externalPath, 0);
-        lmcl.removeCpURLs();
-        targetClass = lmcl.findClass(className);
-        lmcl.addCpURLs();
+
+        // use findResourceInternal first, to validate that
+        // the class is actually found in the container
+        final String dname = className.replace('.', '/') + ".class";
+        File f = lmcl.findResourceInternal(dname);
+
+        if (f != null)
+          // then load the class the regular way (note that if the
+          // class is also found earlier in the CLASSPATH, we don't
+          // load it from the container, but from the jar or class
+          // found earlier)
+          targetClass = lmcl.loadClass(className);
+        else
+          {
+            retSig[0] = "";
+            errCode[0] = CLASS_NOT_FOUND;
+            errDetail[0] = "";
+            return;
+          }
       }
       catch (ClassNotFoundException cnfe)
       {
         retSig[0] = "";
-        errCode[0] = CLASS_NOT_FOUND;//Class not found
+        errCode[0] = CLASS_NOT_FOUND;
         errDetail[0] = "";
         return;
       }
       catch (NoClassDefFoundError cdnfe)
       {
         retSig[0] = "";
-        errCode[0] = CLASS_DEF_NOT_FOUND;//No Class definition found
+        errCode[0] = CLASS_DEF_NOT_FOUND;
         errDetail[0] = "";
         return;
       }
@@ -920,16 +939,117 @@ public class LmUtility {
     }  // Method validateMethod() ends
 
     /**
+     * Returns the generic user id for isolated UDRs. This generic
+     * id is used to store files available to all UDRs and it is
+     * also used as a sandbox for systems that don't have user ids
+     * for isolated UDRs (note that such user ids are not implemented
+     * as of March 2017, when this is written).
+     *
+     * @return: generic isolated UDR user id
+     *
+     **/
+    public static String getPublicUserId()
+    {
+        return "public";
+    }
+
+    /**
+     * Returns the directory in which all UDR-related files should reside
+     *
+     * @return: Root directory for UDR-related files
+     *
+     **/
+    public static Path getSandboxRoot()
+    {
+        return Paths.get(System.getenv("TRAF_HOME"), "udr");
+    }
+
+    /**
+     * Returns the directory in which all UDR-related files for a
+     * particular isolated UDR user id should reside
+     *
+     * @param userid user id for which we return the sandbox root. If empty
+     *               or null, returns the sandbox root for the public user id.
+     * @return: Root directory for UDR-related files for user "user"
+     *
+     **/
+    public static Path getSandboxRootForUser(String userid)
+    {
+        if (userid == null || userid.length() == 0)
+            return getSandboxRootForUser(getPublicUserId());
+
+        return Paths.get(System.getenv("TRAF_HOME"), "udr", userid);
+    }
+
+    /**
+     * Returns the directory in which all external libraries for a
+     * particular isolated UDR user id should reside
+     *
+     * @param userid user id for which we return the libraries dir. If empty
+     *               or null, returns the sandbox root for the public user id.
+     * @return: external libs dir for UDR-related files for user "user"
+     *
+     **/
+    public static Path getExternalLibsDirForUser(String userid)
+    {
+        if (userid == null || userid.length() == 0)
+            return getExternalLibsDirForUser(getPublicUserId());
+
+        return Paths.get(System.getenv("TRAF_HOME"), "udr", userid, "external_libs");
+    }
+
+    static class JarFilter implements FilenameFilter {
+        JarFilter()
+        {}
+
+        @Override
+        public boolean accept(File dir, String name) {
+            return name.endsWith(".jar");
+        }
+    }
+
+    /**
      * Creates an object of LmClassLoader class.
      * @param  path   external path for CL
-     * @param  debug  debug flag
+     * @param  debug  debug flag (currently ignored)
      * @return: Object of LmClassLoader type
      *
      **/
     public static LmClassLoader createClassLoader(String path, int debug)
+        throws Exception
     {
-      LmClassLoader lmcl = new LmClassLoader(path, debug);
-      return lmcl;
+        // We pass a list of URLs to search to the class loader:
+        // - The first URL is the path provided as an argument, that
+        //   is the actual container name
+        // - The second URL is the external libs dir, returned by
+        //   getExternalLibsDirForUser()
+        // - Following are jars that are available to the UDR,
+        //   stored in the external libs dir
+
+        Path extraJarPath = getExternalLibsDirForUser(getPublicUserId());
+        File extraJarDir = extraJarPath.toFile();
+        final int numStdURLs = 2; // 2 URLs that are always provided
+        int numExtraURLs = 0;     // URLs of the jar files in the libs dir
+        File[] extraJarFiles = null;
+        URL[] extraJarURLs = null;
+
+        if (extraJarDir.isDirectory())
+            {
+                extraJarFiles = extraJarDir.listFiles(new JarFilter());
+                numExtraURLs += extraJarFiles.length;
+            }
+
+        extraJarURLs = new URL[numStdURLs+numExtraURLs];
+
+        // add the two standard URLs
+        extraJarURLs[0] = new File(path).toURI().toURL();
+        extraJarURLs[1] = extraJarDir.toURI().toURL();
+        // add any jars that we collected above
+        for (int f=0; f<numExtraURLs; f++)
+            extraJarURLs[f+numStdURLs] = extraJarFiles[f].toURI().toURL();
+
+        LmClassLoader lmcl = new LmClassLoader(extraJarURLs);
+        return lmcl;
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/da1b7b8f/core/sql/src/main/java/org/trafodion/sql/udr/predef/JDBCUDR.java
----------------------------------------------------------------------
diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/predef/JDBCUDR.java b/core/sql/src/main/java/org/trafodion/sql/udr/predef/JDBCUDR.java
index 04faccb..3cdd747 100644
--- a/core/sql/src/main/java/org/trafodion/sql/udr/predef/JDBCUDR.java
+++ b/core/sql/src/main/java/org/trafodion/sql/udr/predef/JDBCUDR.java
@@ -26,7 +26,8 @@ under the License.
  * Invocation (all arguments are strings):
  *
  * select ... from udf(JDBC(
- *    <name of JDBC driver jar>,
+ *    <name of JDBC driver jar>, // Not really needed if the jar is stored in
+ *                               // $TRAF_HOME/udr/public/external_libs
  *    <name of JDBC driver class in the jar>,
  *    <connection string>,
  *    <user name>,
@@ -58,13 +59,10 @@ package org.trafodion.sql.udr.predef;
 
 import org.trafodion.sql.udr.*;
 import java.sql.*;
-import java.util.Vector;
-import java.lang.Math;
-import java.net.URL;
-import java.net.URLClassLoader;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.io.PrintStream;
+import java.util.Vector;
+import java.lang.Math;
 import java.util.Properties;
 import java.util.logging.Logger;
 
@@ -98,16 +96,14 @@ class JDBCUDR extends UDR
         {
           try {
             Path driverJarPath = Paths.get(driverJar_);
-            Path sandBoxPath = Paths.get(System.getenv("TRAF_HOME"), "udr", "external_libs");
-            URLClassLoader jdbcJarLoader = null;
-            URL jarClassPath[] = new URL[1];
 
             // for security reasons, we sandbox the allowed driver jars
             // into $TRAF_HOME/export/lib/udr/external_libs
             driverJarPath = driverJarPath.normalize();
             if (driverJarPath.isAbsolute())
               {
-                if (! driverJarPath.startsWith(sandBoxPath))
+                if (! driverJarPath.startsWith(
+                                  LmUtility.getSandboxRootForUser(null)))
                   throw new UDRException(
                     38010,
                     "The jar name of the JDBC driver must be a name relative to %s, got %s",
@@ -115,26 +111,46 @@ class JDBCUDR extends UDR
                     driverJar_);
               }
             else
-              driverJarPath = sandBoxPath.resolve(driverJarPath);
-
-            // Create a class loader that can access the
-            // jar file specified by the caller.
-            jarClassPath[0] = driverJarPath.toUri().toURL();
-            jdbcJarLoader = new URLClassLoader(
-                jarClassPath,
-                this.getClass().getClassLoader());
+              driverJarPath = LmUtility.getExternalLibsDirForUser(null).resolve(
+                    driverJarPath);
+
+            // Create a class loader that can access the jar file
+            // specified by the caller. Note that this is only needed
+            // because the JDBC UDR is a predefined UDR and is loaded
+            // by the standard class loader. If it were a regular UDR,
+            // it would have been loaded by LmClassLoader and we would
+            // not need to create an LmClassLoader here.
+            LmClassLoader jdbcJarLoader = LmUtility.createClassLoader(
+                                               driverJarPath.toString(),0);
+
+            Driver d = (Driver) Class.forName(driverClassName_,
+                                              true,
+                                              jdbcJarLoader).newInstance();
 
             // go through an intermediary driver, since the DriverManager
             // will not accept classes that are not loaded by the default
             // class loader
-            Driver d = (Driver) Class.forName(driverClassName_, true, jdbcJarLoader).newInstance();
             DriverManager.registerDriver(new URLDriver(d));
             conn_ = DriverManager.getConnection(connectionString_,
                                                 username_,
                                                 password_);
             return conn_;
           }
-          catch(Exception e) {
+          catch (ClassNotFoundException cnf) {
+              throw new UDRException(
+                38020,
+                "JDBC driver class %s not found. Please make sure the JDBC driver jar is
stored in %s. Message: %s",
+                driverClassName_,
+                System.getenv("TRAF_HOME") + "/udr/public/external_libs",
+                cnf.getMessage());
+          }
+          catch (SQLException se) {
+              throw new UDRException(
+                38020,
+                "SQL exception during connect. Message: %s",
+                se.getMessage());
+          }
+          catch (Exception e) {
               if (debug_)
                   {
                       System.out.println("Debug: Exception during connect:");


Mime
View raw message