[ 
https://issues.apache.org/jira/browse/UIMA-4793?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15427200#comment-15427200
 ] 

Richard Eckart de Castilho edited comment on UIMA-4793 at 8/18/16 9:39 PM:
---------------------------------------------------------------------------

Took me a while to remember in which scenario I could try tracking this down.

I added another fallback on the Thread classloader in the 
MsgLocalizationClassLoader.getResource() method because in that particular case 
I am investigating now, the message bundle properties file fails to be located.

Unfortunately, that fixes the problem only half. There is a second part to the 
problem that I didn't see before.

I am testing in the context of a Groovy script that dynamically loads Maven 
dependencies containing UIMA components and adds them to a dynamic script 
classpath (which I also made accessible through the thread context classloader) 
.

So new fallback to the Thread classloader now fixes the internationalization of 
the exception as long as I print the exception message while I'm still within 
the context of my script (where the Thread classloader is active).

However, if I don't catch the exception in my script and instead let it 
percolate upwards, the Thread classloader gets eventually unset in a finally 
block. So when the exception finally reaches JUnit and JUnit tries to print the 
error message, the resource bundle *again* cannot be resolved.

So I would suggest that the error message should be prepared and cached 
directly in the constructor of the InternationalizedException instead of 
generating it lazily in getLocalizedMessage(). That should then also solve the 
second half of the problem.


was (Author: rec):
Took me a while to remember in which scenario I could try tracking this down.

I added another fallback on the Thread classloader in the 
MsgLocalizationClassLoader.getResource() method because in that particular case 
I am investigating now, the message bundle properties file fails to be located.

Unfortunately, that fixes the problem only half. There is a second part to the 
problem that I didn't see before.

I am testing in the context of a Groovy script that dynamically loads Maven 
dependencies containing UIMA components and adds them to a dynamic script 
classpath (which I also made accessible through the thread context classloader) 
.

So new fallback to the Thread classloader now fixes the internationalization of 
the exception as long as I print the exception message while I'm still within 
the context of my script (where the Thread classloader is active).

However, if I don't catch the exception in my script and instead let it 
percolate upwards, the Thread classloader gets eventually unset in a finally 
block. So when the exception finally reaches JUnit and JUnit tries to print the 
error message, the resource bundle *again* cannot be resolved.

So I would suggest that the error message should be prepared and cached 
directly in the constructor of the InternationalizedException instead of 
generating it lazily in getLocalizedMessage().

> Unable to localize exceptions when using alternative classloader
> ----------------------------------------------------------------
>
>                 Key: UIMA-4793
>                 URL: https://issues.apache.org/jira/browse/UIMA-4793
>             Project: UIMA
>          Issue Type: Bug
>          Components: Core Java Framework
>    Affects Versions: 2.8.1SDK
>            Reporter: Richard Eckart de Castilho
>
> If a component is initialized through a resource manager with a custom 
> classloader, then it may not have access to its localized exception message 
> bundles.
> The reason is, that within the classloader chain, the CL which knows about 
> the Core UIMA framework is at a higher level than the CL used by the resource 
> manager that created the component. The component CL would have access to the 
> message bundle, but InterationalizedException uses it's own classloader (the 
> higher level one that knows about Core UIMA) to load message bundles:
> {noformat}
> // locate the resource bundle for this exception's messages
>          // turn over the classloader of the current object explicitly, so 
> that the
>          // message resolving also works for derived exception classes
>          ResourceBundle bundle = ResourceBundle.getBundle(
>                getResourceBundleName(), aLocale, this.getClass()
>                      .getClassLoader());
> {noformat}
> {noformat}
> Thread [main] (Suspended (exception MissingResourceException))        
>       owns: PrintWriter  (id=92)      
>       owns: ThrowableInformation  (id=93)     
>       owns: ConsoleAppender  (id=94)  
>       owns: RootLogger  (id=95)       
>       ResourceBundle.throwMissingResourceException(String, Locale, Throwable) 
> line: 1564      
>       ResourceBundle.getBundleImpl(String, Locale, ClassLoader, 
> ResourceBundle$Control) line: 1387    
>       ResourceBundle.getBundle(String, Locale, ClassLoader) line: 1082        
>       
> AnalysisEngineProcessException(InternationalizedException).getLocalizedMessage(Locale)
>  line: 240        
>       
> AnalysisEngineProcessException(InternationalizedException).getLocalizedMessage()
>  line: 218      
>       AnalysisEngineProcessException(Throwable).toString() line: 480  
>       String.valueOf(Object) line: 2994       
>       PrintWriter.println(Object) line: 754   
>       Throwable$WrappedPrintWriter.println(Object) line: 764  
>       
> AnalysisEngineProcessException(Throwable).printStackTrace(Throwable$PrintStreamOrWriter)
>  line: 655      
>       AnalysisEngineProcessException(Throwable).printStackTrace(PrintWriter) 
> line: 721        
>       DefaultThrowableRenderer.render(Throwable) line: 60     
>       ThrowableInformation.getThrowableStrRep() line: 87      
>       LoggingEvent.getThrowableStrRep() line: 413     
>       ConsoleAppender(WriterAppender).subAppend(LoggingEvent) line: 313       
>       ConsoleAppender(WriterAppender).append(LoggingEvent) line: 162  
>       ConsoleAppender(AppenderSkeleton).doAppend(LoggingEvent) line: 251      
>       AppenderAttachableImpl.appendLoopOnAppenders(LoggingEvent) line: 66     
>       Logger(Category).callAppenders(LoggingEvent) line: 206  
>       Logger(Category).forcedLog(String, Priority, Object, Throwable) line: 
> 391       
>       Logger(Category).log(String, Priority, Object, Throwable) line: 856     
>       Log4jLogger_impl.log(Level, String, Throwable) line: 272        
>       PrimitiveAnalysisEngine_impl.callAnalysisComponentProcess(CAS) line: 
> 417        
>       PrimitiveAnalysisEngine_impl.processAndOutputNewCASes(CAS) line: 308    
>       PrimitiveAnalysisEngine_impl(AnalysisEngineImplBase).process(CAS) line: 
> 269     
>       PrimitiveAnalysisEngine_impl(AnalysisEngineImplBase).process(JCas) 
> line: 284    
>       AnalysisEngine$process.call(Object, Object) line: not available 
> ...
> {noformat}
> The IMHO best way would be if UIMA would at try here to use the thread's 
> context classloader - and maybe that UIMA actually sets the thread context 
> classloader to the resource manager CL while running components... in my 
> case, I already do that outside UIMA atm, so searching the thread CL would be 
> sufficient for me atm.
> See also: https://issues.apache.org/jira/browse/UIMA-3692



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to