Details

    • Type: Improvement Improvement
    • Status: Reopened
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 0.5
    • Fix Version/s: 0.6
    • Labels:
      None
    • Environment:

      Oracle Java stored procedure (oracle versions 8i -> 11g) Any OS

      Description

      First of all, excuse my bad english (I'm an spanish speaker)
      Starting in version 8i, Oracle provides an embedded JVM inside th databases, in order to develop a stored procedure inJava language, later to be invoked via PL/SQL.

      Saddly, the JVM has some quirks, for example an somehow brain-damaged classLoader (oracle.aurora.rdbms.OracleClassLoader).
      This JVM stores the classes inside table objects (very reasonable).

      This leads to some problem: the resources haves some strange URL (example: jserver:/resource/schema/NAME_OF_THE_SCHEMA/ar.com.menhir.config.properties).
      It will be not problema at all except because it's brain damage insist in telling that the above URL works only with RESOURCES and not with CLASSES!!

      for example, the following example

      private static void getData ( ClassLoader cl , String str )

      { System.out.println(str +".class" + "-> "+cl.getResource(str+".class")); System.out.println(str +".class" + "-> "+ClassLoader.getSystemResource(str+".class")); }

      ...
      getData(Test.class.getClassLoader(),"ar.com.menhir.wstest.Test");
      ...
      gives this 2 results:
      with normal classLoader ( sun.misc.Launcher$AppClassLoader)

      ar/com/menhir/wstest/Test.class-> file:/C:/Users/LeoB/workspace2/prueba/bin/ar/com/menhir/wstest/Test.class
      ar/com/menhir/wstest/Test.class-> file:/C:/Users/LeoB/workspace2/prueba/bin/ar/com/menhir/wstest/Test.class

      with oracle classLoader (oracle.aurora.rdbms.OracleClassLoader)

      ar/com/menhir/wstest/Test.class-> null
      ar/com/menhir/wstest/Test.class-> null

      The problem arises in org.apache.commons.discovery.resource.classes.DiscoverClasses, where the line 60

      final String resourceName = className.replace('.','/') + ".class";

      points to a nonexistente resource.

      my workaround was to hack this class with the following:

      final String resourceName = ar.com.menhir.oracle.resources.Utils.getResourcePrefix(className).replace('.','/') + ".class";

      where getResourcePrefix gets the correct prefix for this class.

      You must note that this is a somehow brutal way of solving. I'm interested in contribute with the wright way, but I'm not very sure of where to start.
      Could you please help me?

      Thank you
      Leo Blumencweig

        Activity

        Hide
        Simone Tripodi added a comment -

        Any hint for this issue? I don't have an Oracle JVM and there is no chance I'll install one, any suggestion?

        Show
        Simone Tripodi added a comment - Any hint for this issue? I don't have an Oracle JVM and there is no chance I'll install one, any suggestion?
        Hide
        Sebb added a comment -

        The Javadoc for ClassLoader#getResource() says

        URL java.lang.ClassLoader.getResource(String name)

        Finds the resource with the given name. A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.

        The name of a resource is a '/'-separated path name that identifies the resource.

        This does not mention classes, so it may just be chance that the Sun JVM treats classes the same way as resources.

        Show
        Sebb added a comment - The Javadoc for ClassLoader#getResource() says URL java.lang.ClassLoader.getResource(String name) Finds the resource with the given name. A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code. The name of a resource is a '/'-separated path name that identifies the resource. This does not mention classes, so it may just be chance that the Sun JVM treats classes the same way as resources.
        Hide
        Sebb added a comment -

        I.e. Discovery is probably making an incorrect assumption about the behaviour of ClassLoader.getResource().

        It appears that the Oracle embedded JVM is not breaking the API contract when it treats classes differently from resources; classes are rather different from resources.

        Show
        Sebb added a comment - I.e. Discovery is probably making an incorrect assumption about the behaviour of ClassLoader.getResource(). It appears that the Oracle embedded JVM is not breaking the API contract when it treats classes differently from resources; classes are rather different from resources.
        Hide
        Simone Tripodi added a comment -

        Classes are data, the JVM shouldn't discriminate resources by the type... the tense

        A resource is some data (images, audio, text, etc)

        is so generic that, even if it doesn't explicitly mention classes, it suggests that classes shouldn't be threaded in a different way...

        What did I loose? I googled a little but didn't find anything useful, any idea?

        Show
        Simone Tripodi added a comment - Classes are data, the JVM shouldn't discriminate resources by the type... the tense A resource is some data (images, audio, text, etc ) is so generic that, even if it doesn't explicitly mention classes, it suggests that classes shouldn't be threaded in a different way... What did I loose? I googled a little but didn't find anything useful, any idea?
        Hide
        Sebb added a comment -

        AIUI, classes are not data.

        Also, resource names use /-separated path names - classes do not.

        Show
        Sebb added a comment - AIUI, classes are not data. Also, resource names use /-separated path names - classes do not.
        Hide
        Simone Tripodi added a comment -

        AFAIK when loading an URL with this (simplified) method

        Class<?> clazz = ...;
        String className = clazz.getName();
        String resourceName = className.replace('.','/') + ".class";
        URL resource = clazz.getClassLoader().getResource(resourceName);
        

        the class is data resource, it shouldn't be different than loading a txt or jpg...

        Show
        Simone Tripodi added a comment - AFAIK when loading an URL with this (simplified) method Class <?> clazz = ...; String className = clazz.getName(); String resourceName = className.replace('.','/') + ".class" ; URL resource = clazz.getClassLoader().getResource(resourceName); the class is data resource, it shouldn't be different than loading a txt or jpg...
        Hide
        Simone Tripodi added a comment -

        Seb, sorry for the misunderstanding, I just realized I spoke about a totally different topic, apologizes
        This issue should be closed as INVALID. WDYT?

        Show
        Simone Tripodi added a comment - Seb, sorry for the misunderstanding, I just realized I spoke about a totally different topic, apologizes This issue should be closed as INVALID. WDYT?
        Hide
        Sebb added a comment -

        No, I don't think it's invalid.

        This issue looks remarkably similar to DISCOVERY-6 which AFAICT is also about (not) finding a class with getResource().

        Why not just use the protectionDomain method, i.e. don't bother with using getResource() for a class?

        Or at least, if

        102 : url = loader.getResource(resourceName);

        returns null, then also try the protectionDomain method.

        Show
        Sebb added a comment - No, I don't think it's invalid. This issue looks remarkably similar to DISCOVERY-6 which AFAICT is also about (not) finding a class with getResource(). Why not just use the protectionDomain method, i.e. don't bother with using getResource() for a class? Or at least, if 102 : url = loader.getResource(resourceName); returns null, then also try the protectionDomain method.
        Hide
        Simone Tripodi added a comment -

        fixed on trunk, see DiscoverClasses r1090700 for review, thanks Seb for reviewing!

        Show
        Simone Tripodi added a comment - fixed on trunk, see DiscoverClasses r1090700 for review, thanks Seb for reviewing!
        Hide
        Leo Blumencweig added a comment -

        Thank you people! I'll try it right now

        Show
        Leo Blumencweig added a comment - Thank you people! I'll try it right now
        Hide
        Simone Tripodi added a comment -

        Hola Leo, any update on it? Did the patch work?

        Show
        Simone Tripodi added a comment - Hola Leo, any update on it? Did the patch work?
        Hide
        Leo Blumencweig added a comment -

        I'm on it, but constructing the right enviroment is a little bit complicated. I'm sure it will be ready for tomorrow +/- 1 day

        Show
        Leo Blumencweig added a comment - I'm on it, but constructing the right enviroment is a little bit complicated. I'm sure it will be ready for tomorrow +/- 1 day
        Hide
        Simone Tripodi added a comment -

        thanks for your help!!!

        Show
        Simone Tripodi added a comment - thanks for your help!!!
        Hide
        Leo Blumencweig added a comment -

        No joy.

        It seems that the key is that the CodeSource is unable to obtain a "location" (ie, getLocation returns null)

        I'm not quite sure why is that happening, but I'm trying to dig a little bit deeper (it's a hard to debug enviroment, only way to do it is's System.out.println(...) )

        I think that for thusday I'll will have some more insights or (I hope) a solution

        In the mean time, any ideas, no matter how improbale, will be VERY APPRECIATED!!!

        Show
        Leo Blumencweig added a comment - No joy. It seems that the key is that the CodeSource is unable to obtain a "location" (ie, getLocation returns null) I'm not quite sure why is that happening, but I'm trying to dig a little bit deeper (it's a hard to debug enviroment, only way to do it is's System.out.println(...) ) I think that for thusday I'll will have some more insights or (I hope) a solution In the mean time, any ideas, no matter how improbale, will be VERY APPRECIATED!!!
        Hide
        Simone Tripodi added a comment -

        I had a pvt dialog with Leo and looks like the JVM he's using requires the {{jserver:/resource/schema/$

        {schema}

        /$

        {resource}

        }} pattern to resolve resources in the classpath.
        I propose to overlook it for 0.5 release and postpone for newer versions.
        WDYT?

        Show
        Simone Tripodi added a comment - I had a pvt dialog with Leo and looks like the JVM he's using requires the {{jserver:/resource/schema/$ {schema} /$ {resource} }} pattern to resolve resources in the classpath. I propose to overlook it for 0.5 release and postpone for newer versions. WDYT?
        Hide
        Sebb added a comment -

        I take it you mean classes in the classpath, not resources in the classpath? Classes are not resources.

        Show
        Sebb added a comment - I take it you mean classes in the classpath, not resources in the classpath? Classes are not resources.
        Hide
        Simone Tripodi added a comment -

        Hi Seb,
        situation is that in DiscoverClasses:

        final String resourceName = className.replace('.','/') + ".class";
        ...
        URL url = null;
        
        try {
            url = loader.getResource(resourceName);
        } catch (UnsupportedOperationException e) {
            // ignore
        }
        
        if (url == null) {
            try {
                CodeSource codeSource = loader.loadClass(className)
                    .getProtectionDomain()
                    .getCodeSource();
                if (codeSource != null) {
                    url = new URL(codeSource.getLocation(), resourceName);
                }
                // else keep url null
            } catch (Exception le) {
                // keep url null
            }
        }
        

        the fact is that inside Leo's JVM both methods fails; the only chance we can get it works, is modifying the resourceName prefix:

        final String resourceName = "jserver:/resource/schema/${schema}/" + className.replace('.','/') + ".class";
        

        since it could require some existing code modification, I suggest to postpone this issue for next release.
        WDYT?

        Show
        Simone Tripodi added a comment - Hi Seb, situation is that in DiscoverClasses: final String resourceName = className.replace('.','/') + ".class" ; ... URL url = null ; try { url = loader.getResource(resourceName); } catch (UnsupportedOperationException e) { // ignore } if (url == null ) { try { CodeSource codeSource = loader.loadClass(className) .getProtectionDomain() .getCodeSource(); if (codeSource != null ) { url = new URL(codeSource.getLocation(), resourceName); } // else keep url null } catch (Exception le) { // keep url null } } the fact is that inside Leo's JVM both methods fails; the only chance we can get it works, is modifying the resourceName prefix: final String resourceName = "jserver:/resource/schema/${schema}/" + className.replace('.','/') + ".class" ; since it could require some existing code modification, I suggest to postpone this issue for next release. WDYT?
        Hide
        Sebb added a comment -

        I agree that this problem is not related to the current tidy-up of DISCOVERY, so fixing it can be postponed.

        But given that the problem is now known, it should at least be mentioned in the release notes.

        Show
        Sebb added a comment - I agree that this problem is not related to the current tidy-up of DISCOVERY, so fixing it can be postponed. But given that the problem is now known, it should at least be mentioned in the release notes.
        Hide
        Leo Blumencweig added a comment -

        I think that the problem it's restricted to only one JVM, that in fact appears to be broken.
        If you people think that it's OK, I volunter for it, but I since it's my first contribution to the project, I will need some (a lot of) guidance.

        BTW, I whish to thanks a lot to Simone for his patience and good mood.

        Show
        Leo Blumencweig added a comment - I think that the problem it's restricted to only one JVM, that in fact appears to be broken. If you people think that it's OK, I volunter for it, but I since it's my first contribution to the project, I will need some (a lot of) guidance. BTW, I whish to thanks a lot to Simone for his patience and good mood.
        Hide
        Sebb added a comment -

        In my opinion, the fact that the Oracle JVM does not allow classes to be found using the getResource() method does not mean that the Oracle JVM is broken. Nor is it broken if ProtectionDomain#getCodeSource() returns null, as that is specifically allowed.

        As far as I can tell, the fact that the current code works for some JVMs is a by-product of their implementation, rather than a requirement.

        Show
        Sebb added a comment - In my opinion, the fact that the Oracle JVM does not allow classes to be found using the getResource() method does not mean that the Oracle JVM is broken. Nor is it broken if ProtectionDomain#getCodeSource() returns null, as that is specifically allowed. As far as I can tell, the fact that the current code works for some JVMs is a by-product of their implementation, rather than a requirement.
        Hide
        Leo Blumencweig added a comment -

        Sebb, it's not only that you can't use getResource() to found classes. In fact, I found absoutely no way to found the origin of some class. That is:

        1) I load the class
        2) I cannot tell from where the class came (network, jar, database, jar in the database ...).

        There is only a partial form, that is assuming it's in some schema of the database and then finding the schema.

        What do you think?

        Thanks
        Leo

        Show
        Leo Blumencweig added a comment - Sebb, it's not only that you can't use getResource() to found classes. In fact, I found absoutely no way to found the origin of some class. That is: 1) I load the class 2) I cannot tell from where the class came (network, jar, database, jar in the database ...). There is only a partial form, that is assuming it's in some schema of the database and then finding the schema. What do you think? Thanks Leo
        Hide
        Sebb added a comment -

        If it's not possible using the defined Java API, it's not possible.

        It does not seem right to add special code to support the Oracle JVM.

        However, it might be possible to provide an overridable method to convert a class name into a form that works with getResource().

        Show
        Sebb added a comment - If it's not possible using the defined Java API, it's not possible. It does not seem right to add special code to support the Oracle JVM. However, it might be possible to provide an overridable method to convert a class name into a form that works with getResource().
        Hide
        Leo Blumencweig added a comment -

        I agree with you. Where do you suggest to put that overridable method?

        Show
        Leo Blumencweig added a comment - I agree with you. Where do you suggest to put that overridable method?
        Hide
        Phil Steitz added a comment -

        From comments, it looks like this issue is actually still open and needs to be assigned a later release for resolution.

        Show
        Phil Steitz added a comment - From comments, it looks like this issue is actually still open and needs to be assigned a later release for resolution.
        Hide
        Ruslan added a comment -

        Sybase Adaptive Enterprise Server (ASE) 15.5 have a similar problems:

        • ClassLoader.getResource() for classes returns NULL.
        • ProtectionDomain#getCodeSource() returns something which is not a valid URI.

        I believe there is no point in calling ProtectionDomain#getCodeSource().
        The only reason to store URI is to uniquely identify loaded class.
        I propose following replacement:

        Class cls = loader.loadClass(className);
        if (cls != null) {
        // Construct some synthetic never used URL
        url = new URL(new URL("http://localhost/ClassLoader-" + loader.hashCode() + "/somewhere/"), resourceName);
        }
        
        Show
        Ruslan added a comment - Sybase Adaptive Enterprise Server (ASE) 15.5 have a similar problems: ClassLoader.getResource() for classes returns NULL. ProtectionDomain#getCodeSource() returns something which is not a valid URI. I believe there is no point in calling ProtectionDomain#getCodeSource(). The only reason to store URI is to uniquely identify loaded class. I propose following replacement: Class cls = loader.loadClass(className); if (cls != null ) { // Construct some synthetic never used URL url = new URL( new URL( "http: //localhost/ ClassLoader -" + loader.hashCode() + "/somewhere/" ), resourceName); }
        Hide
        Simone Tripodi added a comment -

        Thanks a lot for the followup - could you please submit a patch? It would be easier for me checking the modifications in!
        TIA!

        Show
        Simone Tripodi added a comment - Thanks a lot for the followup - could you please submit a patch? It would be easier for me checking the modifications in! TIA!
        Hide
        Ruslan added a comment -

        Patch against 0.5 which uses safe to use loadClass() + some dummy URL construction.

        Show
        Ruslan added a comment - Patch against 0.5 which uses safe to use loadClass() + some dummy URL construction.
        Hide
        Ruslan added a comment -

        Can`t attach path, here is a link http://pastebin.com/T9gjiedx
        I grant license to ASF for inclusion in ASF works.

        Show
        Ruslan added a comment - Can`t attach path, here is a link http://pastebin.com/T9gjiedx I grant license to ASF for inclusion in ASF works.
        Hide
        Simone Tripodi added a comment -

        I see you attached patches twice, what's wrong with plain old files? Every user should be able to attach patches!

        Thanks anyway, I'll review it as soon as I get the chance.

        Show
        Simone Tripodi added a comment - I see you attached patches twice, what's wrong with plain old files? Every user should be able to attach patches! Thanks anyway, I'll review it as soon as I get the chance.
        Hide
        Simone Tripodi added a comment -

        Apologize but I feel confused. What

        new URL(new URL("http://localhost/ClassLoader-" + loader.hashCode() + "/somewhere/"), resourceName);
        

        that hardcoded URL should mean? Can you please clarify me the strategy?
        TIA!

        Show
        Simone Tripodi added a comment - Apologize but I feel confused. What new URL( new URL( "http: //localhost/ ClassLoader -" + loader.hashCode() + "/somewhere/" ), resourceName); that hardcoded URL should mean? Can you please clarify me the strategy? TIA!
        Hide
        Ruslan added a comment -

        It is unique URL for this class which should never be used.

        I believe there is no such case to actually call org.apache.commons.discovery.Resource.getResource() on org.apache.commons.discovery.ResourceClass instances.

        Maybe it is better to override getResource() and getResourceAsStream() in ResourceClass to make them throw NotSupportedOperationException. Maybe it is better to do only if real URL of class can`t be determined by using ProtectionDomain#getCodeSource().

        Show
        Ruslan added a comment - It is unique URL for this class which should never be used. I believe there is no such case to actually call org.apache.commons.discovery.Resource.getResource() on org.apache.commons.discovery.ResourceClass instances. Maybe it is better to override getResource() and getResourceAsStream() in ResourceClass to make them throw NotSupportedOperationException. Maybe it is better to do only if real URL of class can`t be determined by using ProtectionDomain#getCodeSource().

          People

          • Assignee:
            Simone Tripodi
            Reporter:
            Leo Blumencweig
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:

              Time Tracking

              Estimated:
              Original Estimate - 504h
              504h
              Remaining:
              Remaining Estimate - 504h
              504h
              Logged:
              Time Spent - Not Specified
              Not Specified

                Development