Re: [Q] How to load Clojure as part of Wildfly module?

2019-02-07 Thread Kimmo Koskinen
Hi!

I ran into the same issue while helping a colleague in working on the 
[sonar-clojure Sonarqube|https://github.com/hjhamala/sonar-clojure/] 
plugin. A quick search on Clojure JIRA reveals couple of discussions, [this 
one|https://dev.clojure.org/jira/browse/CLJ-260?focusedCommentId=23453=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-23453]
 
maybe the most relevant.

In our case, we also wrote a piece of Java code to set up the threads 
context classloader so that RT can load itself.

ClassLoader ccl = Thread.currentThread().getContextClassLoader();
   try {
   Thread.currentThread().setContextClassLoader(this.getClass().
getClassLoader());
   RT.init();
   Var.pushThreadBindings(RT.map(RT.USE_CONTEXT_CLASSLOADER, RT.F));
   } finally {
   Thread.currentThread().setContextClassLoader(ccl);
   }



I think it might be neat to have a way to allow the RT to load itself from 
the classloader that loaded the RT class itself, instead of the thread's 
context classloader. A system property might be enough, but I started to 
think about a way to specify this even in a gen-classed. This would need 
less "glue", since a gen-classed class causes the RT class to load, in 
which case there is a need for callsite glue to setup the thread's context 
classloader.

Maybe a new JIRA ticket might be a good place for the discussion :)

- Kimmo

torstai 7. helmikuuta 2019 23.02.24 UTC+2 henrik42 kirjoitti:
>
> Rastko - thanks for the reply. My 
> /modules/buttle/main/module.xml looks like this:
>
> 
> 
>   
> 
>   
>   
> 
>  
>   
>  
>
> And the driver in standalone.xml:
>
> 
>   
> 
>
> The loading of my classes incl. clojure.lang.RT works "in
> principle". Only when Clojure uses the TCCL to load clojure/core.clj 
> things fail. To see what's
> happening I changed
> java/buttle/SetContextClassLoaderInStaticInitializer.java to:
>
> package buttle;
> public class SetContextClassLoaderInStaticInitializer {
> static {
> ClassLoader tccl = 
> Thread.currentThread().getContextClassLoader();
> System.out.println("tccl = " + tccl);
> System.out.println("tccl sees clojure/core.clj at " + 
> tccl.getResource("clojure/core.clj"));
> ClassLoader myCl = 
> SetContextClassLoaderInStaticInitializer.class.getClassLoader();
> System.out.println("myCl = " + myCl);
> System.out.println("myCl sees clojure/core.clj at " + 
> myCl.getResource("clojure/core.clj"));
> 
> Thread.currentThread().setContextClassLoader(SetContextClassLoaderInStaticInitializer.class.getClassLoader());
> }
> }
>
> I get:
>
> tccl = ModuleClassLoader for Module "org.jboss.as.controller" version 
> 4.0.0.Final from local module loader @6adca536
>(finder: local module finder @357246de (roots: 
> C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base))
> tccl sees clojure/core.clj at null
> myCl = ModuleClassLoader for Module "buttle" from local module loader 
> @6adca536 (finder: local module finder @357246de
>(roots: 
> C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base))
> myCl sees clojure/core.clj at 
> jar:file:/C:/henrik/wildfly-12.0.0.Final/modules/buttle/main/./buttle-standalone.jar!/clojure/core.clj
>
> I checked that my class and clojure.lang.RT are loaded with the same 
> classloader. So the TCCL which Wildfly puts into
> place cannot load clojure/core.clj. But the (module) classloader which 
> loaded my class and clojure.lang.RT CAN load it. That's
> why I came up with the idea of replacing the TCCL before 
> clojure.lang.RT runs.
>
> I believe that the way Wildfly uses the different classloaders is 
> absolutly on purpose. In [1] you find
> arguments for why libraries should not use the TCCL for certain things. 
> And one could argue, that Clojure
> is doing it the wrong way.
>
> I believe that the existence of clojure.core/*use-context-classloader* is 
> due to someone realizing that there are
> cases when you cannot use the TCCL (like in mine). In my case though I 
> just can't set that var because of the chicken-egg-problem
> as I pointed out.
>
> I think that adding additional dependencies or adding exports won't
> change the Module-"org.jboss.as.controller"-classloader. But I'll check 
> tomorrow.
>
> One solution that comes to mind is to change clojure.lang/RT so that the 
> *use-context-classloader* var is not initialized to
> true but to (Boolean/parseBoolean (System/getProperty 
> "clojure.use-context-classloader" "true"))
>
> Henrik
>
> [1] https://developer.jboss.org/wiki/ModuleCompatibleClassloadingGuide
>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that 

Re: [Q] How to load Clojure as part of Wildfly module?

2019-02-07 Thread henrik42
Rastko - thanks for the reply. My 
/modules/buttle/main/module.xml looks like this:



  

  
  

 
  
 

And the driver in standalone.xml:


  


The loading of my classes incl. clojure.lang.RT works "in
principle". Only when Clojure uses the TCCL to load clojure/core.clj things 
fail. To see what's
happening I changed
java/buttle/SetContextClassLoaderInStaticInitializer.java to:

package buttle;
public class SetContextClassLoaderInStaticInitializer {
static {
ClassLoader tccl = 
Thread.currentThread().getContextClassLoader();
System.out.println("tccl = " + tccl);
System.out.println("tccl sees clojure/core.clj at " + 
tccl.getResource("clojure/core.clj"));
ClassLoader myCl = 
SetContextClassLoaderInStaticInitializer.class.getClassLoader();
System.out.println("myCl = " + myCl);
System.out.println("myCl sees clojure/core.clj at " + 
myCl.getResource("clojure/core.clj"));

Thread.currentThread().setContextClassLoader(SetContextClassLoaderInStaticInitializer.class.getClassLoader());
}
}

I get:

tccl = ModuleClassLoader for Module "org.jboss.as.controller" version 
4.0.0.Final from local module loader @6adca536
   (finder: local module finder @357246de (roots: 
C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base))
tccl sees clojure/core.clj at null
myCl = ModuleClassLoader for Module "buttle" from local module loader 
@6adca536 (finder: local module finder @357246de
   (roots: 
C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base))
myCl sees clojure/core.clj at 
jar:file:/C:/henrik/wildfly-12.0.0.Final/modules/buttle/main/./buttle-standalone.jar!/clojure/core.clj

I checked that my class and clojure.lang.RT are loaded with the same 
classloader. So the TCCL which Wildfly puts into
place cannot load clojure/core.clj. But the (module) classloader which 
loaded my class and clojure.lang.RT CAN load it. That's
why I came up with the idea of replacing the TCCL before 
clojure.lang.RT runs.

I believe that the way Wildfly uses the different classloaders is absolutly 
on purpose. In [1] you find
arguments for why libraries should not use the TCCL for certain things. And 
one could argue, that Clojure
is doing it the wrong way.

I believe that the existence of clojure.core/*use-context-classloader* is 
due to someone realizing that there are
cases when you cannot use the TCCL (like in mine). In my case though I just 
can't set that var because of the chicken-egg-problem
as I pointed out.

I think that adding additional dependencies or adding exports won't
change the Module-"org.jboss.as.controller"-classloader. But I'll check 
tomorrow.

One solution that comes to mind is to change clojure.lang/RT so that the 
*use-context-classloader* var is not initialized to
true but to (Boolean/parseBoolean (System/getProperty 
"clojure.use-context-classloader" "true"))

Henrik

[1] https://developer.jboss.org/wiki/ModuleCompatibleClassloadingGuide

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [Q] How to load Clojure as part of Wildfly module?

2019-02-07 Thread Rastko Soskic
Hm, it's been really long a go when I've last dealt with EE container
but could you tell how does your module exports are set in 
module definition? Exports are I believe what defines what
is exposed to the "outside" world. Furthermore, it might be that you should
also add module imports in your app so it is able to see exposed
classes/packages.

I can't tell for sure this could or could not help but that is 
something what I could remember of.

On Wednesday, February 6, 2019 at 10:40:39 PM UTC+1, henrik42 wrote:
>
> Hi,
>
> I'm working on a "proxying JDBC driver" in Clojure [1]. Everything is
> working fine. But I had one problem with the way Clojure
> (i.e. clojure.lang.RT) manages its classloader.
>
> When Wildfly loads my UBERJAR which contains Clojure and
> loads/instanciates my gen-class `buttle.jdbc.Driver` then its static
> initializer will load `clojure.lang.RT`. At this point the current
> thread's context classloader (TCCL; which is put into place by
> Wildfly) does NOT point to the one that is loading my code and the
> TCCL in-fact does not "see" my classes.
>
> So when Clojure/RT then tries to find `clojure/core.clj` it fails
> because Clojure uses the TCCL for loading [2]. I could try to set
> `clojure.core/*use-context-classloader*` to false but this leads to a
> chicken-egg-problem since for doing that, `clojure.lang/RT` would have
> to be loaded in the first place. 
>
> So my question is: is there a nice way out of this?
>
> The workaround I came up with was to compile a Java class [3] which is
> the super class of my gen class [4]. And since static initializers are
> called in order super-class->derived-class the static initializer of
> the super-class is used to set the TCCL to the one that loads my code
> base. After that Clojure finds clojure/core.clj without problems.
>
> Any ideas on how to do without this hack?
>
> Henrik
>
> [1] https://github.com/henrik42/buttle/
> [2] 
> https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2174
> [3] 
> https://github.com/henrik42/buttle/blob/master/java/buttle/SetContextClassLoaderInStaticInitializer.java
> [4] 
> https://github.com/henrik42/buttle/blob/master/src/buttle/driver.clj#L29
>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[Q] How to load Clojure as part of Wildfly module?

2019-02-06 Thread henrik42
Hi,

I'm working on a "proxying JDBC driver" in Clojure [1]. Everything is
working fine. But I had one problem with the way Clojure
(i.e. clojure.lang.RT) manages its classloader.

When Wildfly loads my UBERJAR which contains Clojure and
loads/instanciates my gen-class `buttle.jdbc.Driver` then its static
initializer will load `clojure.lang.RT`. At this point the current
thread's context classloader (TCCL; which is put into place by
Wildfly) does NOT point to the one that is loading my code and the
TCCL in-fact does not "see" my classes.

So when Clojure/RT then tries to find `clojure/core.clj` it fails
because Clojure uses the TCCL for loading [2]. I could try to set
`clojure.core/*use-context-classloader*` to false but this leads to a
chicken-egg-problem since for doing that, `clojure.lang/RT` would have
to be loaded in the first place. 

So my question is: is there a nice way out of this?

The workaround I came up with was to compile a Java class [3] which is
the super class of my gen class [4]. And since static initializers are
called in order super-class->derived-class the static initializer of
the super-class is used to set the TCCL to the one that loads my code
base. After that Clojure finds clojure/core.clj without problems.

Any ideas on how to do without this hack?

Henrik

[1] https://github.com/henrik42/buttle/
[2] 
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2174
[3] 
https://github.com/henrik42/buttle/blob/master/java/buttle/SetContextClassLoaderInStaticInitializer.java
[4] https://github.com/henrik42/buttle/blob/master/src/buttle/driver.clj#L29

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.