2

I have a standalone library ( jar file) that is added to the application server classpath to monitor all the running applications in the JVM and send email when some issue happens.

the jar file have all the dependencies bundled in the jar (using the maven-shade-plugin) including the javamail jar file.

When one of the other webapplications in the appserver have javamail as a dependency, some dependency conflict happens with the javamail in my jar file and I get an exception

MessagingException :javax.mail.NoSuchProviderException: No provider for smtp 

How can I solve this conflict knowing that I can't modify the running appplications. I only have control over my jar file.

Edit:

I debugged through the javamail API. and I found out that the javax.mail.Session construct a new object of type com.sun.mail.smtp.SMTPTransport using reflection and pass two parameters to the constructor, but rather than using SMTPTransport located in the same jar file it tries to use SMTPTransport from the other mail.jar located in one of the deployed apps.

Sammy
  • 4,538
  • 8
  • 33
  • 52

3 Answers3

3

In tomcat 7, by default web applications will look first for classes on this order:

  1. first on WEB-INF/classes
  2. then inside jars in WEB-INF/lib
  3. and if the class was not found only then in YOUR_SERVER_HOME/lib
  4. Then on the system classloaders, as described here

Class versions from other WARs (on classes / WEB-INF/lib) cannot be visible from inside another WAR.

Can you let us know of further info that could help track down the problem:

  • what does the standalone library do in more detail, how does it monitor the other applications?

  • how is the standalone library added to the server classpath? Is it copied on YOUR_SERVER_HOME/lib, or is a folder added to the server classpath via shared.loader or common.loader properties of catalina.properties

  • does each WAR application provide it's own mail jars on WEB-INF/lib, or is the library published at the server level as a JNDI resource such as mentioned here on section Install the JavaMail libraries

  • Is any of the applications in the server NOT running in the default classloading mode that I mentioned above, and is using delegate = true (meaning it will look on the server first and only then on the WAR) ? here is how this would be configured, check for a Resource element in the context.xml or server.xml

Some suggestions for possible solutions:

  1. Install JavaMail on tomcat 7 as a JNDI resource following the installation instructions here on section Install the JavaMail libraries. Have all applications use the JNDI resource as in the tomcat docs, and remove java mail from the standalone library using a shade plugin exclusion. This will always work and it's the most recommended solution.

  2. If you are using Java 7, try to use JHades to troubleshoot the classpath of the different applications. You can do static analysis on the WARs for duplicate classes, or view what are the versions used at runtime of a given class, and which other versions are available.

  3. Since there is no control over the deployment settings of the other applications or their contents, use of JNDI, etc., a solution that will work for sure in all environments and with any application is to refactor the tool so that it does not require mail.jar to be installed on the server. The tool can write an email request to for example a file or a database table, and another WAR deployed on the server would poll the table file and send the mail. Or a bash/bat script is called that itself sends the email on a separate java process.

Performance analysis tools such as Dynatrace are based on JVM agents and use a similar mechanism that does not need the introduction of libraries at the server level, the agent collects data and sends it to a collecting process that stores it somewhere for further analisys, treatment such as send alarms via emails, etc.

Hope this helps, in general I don't see any way to deploy libraries to a EE server and be sure that they will never cause problems to any application on different server types and different application classloading settings.

The best is probably adapt the tool so that it relies on a minimum of libraries deployed on the server, breaking it up into separate modules with only the collecting module running on the server or look into alternatives such as Dynatrace.

Angular University
  • 42,341
  • 15
  • 74
  • 81
  • Thank you the suggestions. I just used Tomcat as an example as it is the app server i m developing on. but the solution should be portable across other appServers. to answer your questions. 1) the standalone library is a library that monitors the web applications performance through AOP and alerts the user when some method execution time is slower than usual. it monitors the other applications through Load Time Weaving. 2) The jar file is added to SERVER_HOME/lib folder, but again the solution should not reply on a specific server's behavior... – Sammy Nov 07 '13 at 13:13
  • 3) the war files could have mail.jar or they may not. I libray would be used by external user's so I have no control over their environments or applications. – Sammy Nov 07 '13 at 13:18
  • This also can be important, what type of load time weaving is being used? is it done via a JVM wide weaver, a spring agent that targets only certain spring contexts, etc ? – Angular University Nov 07 '13 at 14:34
  • it is done by aspectj-weaver. but this shouldn't be the problem. the code that sends the email have nothing to do with the woven classes or the aspectj code. – Sammy Nov 07 '13 at 14:38
  • I really like you last update :) I think to best way is to refactor the code to reply on minimal libraries so my library will only collect the metrics and send them to a Rest Service through http calls so the Rest Service (deployed separately) could handle the analysis and storage of the data. this will insure no conflict between libraries in my module and others deployed in the system. – Sammy Nov 07 '13 at 16:32
0

I'm not familiar with the maven-shade-plugin. Does it package the original jar files in a new jar file? Does it extract the contents of the original jar files and insert the contents into the new jar file? If the latter, it may only be including the class files and not the resource files in META-INF that configure the JavaMail providers.

Of course, the best approach would be to arrange for only one copy of the JavaMail jar file to be included in the server's classpath.

Bill Shannon
  • 29,579
  • 6
  • 38
  • 40
  • The shade plugin extract the content into the original jar and it extract the meta-inf files as well. Unfortunately, I don't know abt the existing applications on the server to arrange for 1 copy. – Sammy Nov 05 '13 at 11:11
  • What server are you using? Java EE application servers will include JavaMail, so there's no need for web applications or your application to include it. – Bill Shannon Nov 05 '13 at 19:39
  • I m using tomcat 7. i don't think it includes a copy of the javamail jar file. – Sammy Nov 05 '13 at 20:57
0

Upgrade the JavaMail version included with Tomcat 7 to JavaMail to 1.5.3 which contains the fix for Bug K6668/E144 -skip unusable Store and Transport classes. You can download the latest snapshot and official releases from the JavaMail reference implementation home page.

jmehrens
  • 10,580
  • 1
  • 38
  • 47