Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mail/Session Resource Factory does not work in Struts application

Tags:

email

tomcat

jndi

I want to use the standard resource factory provided by Tomcat 6.0, which create javax.mail.Sessions instance for me. As described in the JNDI Resource HOW-TO tutorial.

My META-INF/context.xml looks like:

<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true">
    <Resource name="mail/Session" 
          auth="Container" 
          type="javax.mail.Session" 
          mail.smtp.host="smtp.gmail.com"
          mail.smtp.port="587"
          mail.smtp.auth="true"
          mail.smtp.user="[email protected]"
          mail.smtp.password="secretpassword" 
          mail.smtp.starttls.enable="true"/>    
</Context>

I have the next resource-ref in my WEB-INF/web.xml, just before </webapps>. Web.xml validates. I validated using McDowell's way.

<resource-ref>
    <description>Resource reference to a factory for javax.mail.Session instances that may be used for sending electronic mail messages, preconfigured
    to connect to the appropiate SMTP server.
    </description>
    <res-ref-name>mail/Session</res-ref-name>
    <res-type>javax.mail.Session</res-type>
    <res-auth>Container</res-auth>
    </resource-ref>

I am using the next code snipett access my javax.mail.Session object.

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session)envCtx.lookup("mail/Session");
System.out.println("HERE smtp.user: " + session.getProperty("mail.smtp.user"));

I tested it in a sample app and it worked. Unfortunately when I moved the same code to a struts application, I get NULL in the above print statement. I do the context look up in singleton Class called mailer (which is defined in my WEB-INF/classes folder) but I get the same problem if i do the context look up in Struts action class.

I have been thinking about what is different to find the problem. My struts application web.xml is more complicated than simple application's web.xml. It has security-constraint, filters and the Struts Servlet configuration. I position resource-ref just before the servlet definitions. It seems like the resource-ref is being ignored.

I have another issue. If I have the mailapi.jar, needed by the javax.mail.Session, in the myapp/WEB-INF/lib folder I get:

java.lang.NoClassDefFoundError: javax/mail/Authenticator

If I put it in $CATALINA_HOME/lib is found.

Any ideas? I use struts and hibernate. Maybe it has something to do with that.

Debug

I tried to debug it puting the debug attribut in context

<Context reloadable="true" debug="99" ...  

But I do not see anything interesting.

01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log

I tried:

Session session = (Session) initCtx.lookup("java:comp/env/mail/Session");

instead of:

Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session)envCtx.lookup("mail/Session");

But I am still getting a NULL Session object.

Partial Solution

When I put the Resource element inside $CATALINA_HOME/conf/context.xml file, it works.

like image 286
Sergio del Amo Avatar asked Mar 02 '23 01:03

Sergio del Amo


1 Answers

JNDI Lookup code quirks

I've seen multiple issues with not finding JNDI resources. On Websphere (I know, you don't use it, but it's good to know...) you'll have problems with

Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session)envCtx.lookup("mail/Session");

What works (on Websphere) is

Session session = (Session) initCtx.lookup("java:comp/env/mail/Session");

From what you wrote in another answer I understand that this is not your problem - I'm leaving it here for people coming across the same problem under different circumstances later.

Lookup of JNDI Resources from self-spawned threads

Also, access to JNDI resources might depend upon the thread looking up the resources. As far as I remember, threading is not well defined in the servlet api (or Java EE or related areas. It might even be voluntarily and explicitly be non-defined.) Therefor it's not mandatory for the server to provide JNDI resources in threads that you've spawned yourself (again Websphere did bite me with this, I haven't tested Tomcat6 in this regard, earlier versions used to provide JNDI resources to all threads)

You've written that you are looking up JNDI resources from a singleton. If you, at the point of looking up resources, examine the stacktrace (either in your IDE, by throwing an exception or messing with Thread.currentThread().getStacktrace()): is there any Tomcat connector in the stacktrace or is one of your own Thread's run() method at the root of the stacktrace ? This would answer the question behind Jacks question if you are making the lookup from an Action class. (see Jack's answer)

Threads and call-environment part two

Create a new Struts Action and call your JNDI lookup code from there, see if this works if placed as close to struts and within the processing of a http request. If it works here, continue with the steps above.

validity of web.xml

Also, you might want to have a look at the schema definition for web.xml to make sure your resource-ref is positioned correctly. The servlet spec 2.4 is available at jcp.org and should be sufficient to check, even if tomcat implements 2.5.

After all, I believe that tomcat6 validates web.xml, so that you probably already have it at the correct position. (Can't remember, as my IDEs editor complains when I get it wrong, should I need to write a web.xml)

Tomcat debug options

Many context.xml entries honour the attribute 'debug'. Though I believe that low one-digit values are sufficient, I've adopted the habit to add 'debug="99"' to elements like 'Context' or others. You might want to see if this results in some helpful log entries.

Make sure it's not the classpath

As you seem to have fundamentally changed the environment, make sure that you have all required libraries on board - the mail api consists of several jars. Download a new copy and unpack all libraries to $CATALINA_HOME/lib. You might take unused away once it worked with all libraries in there.

Regarding your classpath question:

The reason for finding the class when put into $CATALINA_HOME/lib is, that the connection is done by the server (remember - you've defined it in context.xml which is read by the server in order to start the application), thus the jar must be on the servers classpath - not just on the applications (see the tomcat class loader HOWTO for more information)

EDIT:

Regarding your partial solution:

$CATALINA_HOME/conf/context.xml contains the global "default" context elements. This is not where you want your application specific configuration to be.

The standard position for tomcat is either in the webapps META-INF/context.xml or in an xml file (named as you like, ending .xml) in $CATALINA_HOME/conf/Catalina/localhost/. The later solution is actually prefered with regards to META-INF/context.xml because this way the configuration is independent of the application and doesn't get overwritten when a new application is deployed.

This context usually contains additional attributes like docBase and path:

<Context docBase="/location/where/you/deployed/your/application" path="/app">
  ...
</Context>

This way your application is available at http://servername:8080/app. If you deploy to the $CATALINA_HOME/webapps directory, the docBase value can be relative to webapp. Be careful with regards to race conditions though: Tomcat will autodeploy applications in $CATALINA_HOME/webapps and might create the context file. Also, deleting the webapp in order to deploy a new one might cause tomcat to delete the xml config file.

Therefor - whatever your problem might be: Try if your context definition / application work when placed in $CATALINA_HOME/conf/Catalina/localhost/app.xml . I have the feeling that it's something very simple, where only the last bit of information is missing in order to see the real problem.

like image 56
Olaf Kock Avatar answered Mar 05 '23 19:03

Olaf Kock