Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fix formatting and links.

...

Here are the three most popular ways::

  • Use a classloader's getResource() method to get an url to the properties file and load it into the Properties. The properties file must be located within the webapp classpath (i.e. either WEB-INF/classes/... or in a jar in WEB-INF/lib/).

A challenge is to get the classloader when you are in a static initializer:

No Format

  public class Config {
     private static java.util.Properties prop = new java.util.Properties();
     private static loadProperties() {
          // get class loader
          ClassLoader loader = Config.class.getClassLoader();
          if(loader==null)
            loader = ClassLoader.getSystemClassLoader();

          // assuming you want to load application.properties located in WEB-INF/classes/conf/
          String propFile = "conf/application.properties";
          java.net.URL url = loader.getResource(propFile);
          try{prop.load(url.openStream());}catch(Exception e){System.err.println("Could not load configuration file: " + propFile);}
     }

     //....
     // add your methods here. prop is filled with the content of conf/application.properties

     // load the properties when class is accessed
     static {
        loadProperties();
     }
  }

This method even works in a standalone java application. So it is my preferred way.

...

  • Use a ResourceBundle. See the Java docs for the specifics of how the ResourceBundle class works. Using this method, the properties file must go into the WEB-INF/classes directory or in a jar file contained in the WEB-INF/lib directory.
  • Another way is to use the method getResourceAsStream() from the ServletContext class. This allows you update the file without having to reload the webapp as required by the first method. Here is an example code snippet, without any error trapping:
No Format

// Assuming you are in a Servlet extending HttpServlet
// This will look for a file called "/more/cowbell.properties" relative
// to your servlet Root Context
InputStream is = getServletContext().getResourceAsStream("/more/cowbell.properties");
Properties  p  = new Properties();
p.load(is);
is.close();

...

You cannot share sessions directly across web apps, as that would be a violation of the Servlet Specification. There are workarounds, including using a singleton class loaded from the common classloader repository to hold shared information, or putting some of this shared information in a database or another data store. Some of these approaches have been discussed on the tomcat-user mailing list, whose archives you should search for more information.

...

Here's what you would like to do, but it throws ClassCastException:

No Format

MyPrincipal p = request.getUserPrincipal();
String emailAddress = p.getEmailAddress();

Here are 4 ways you might get around the classloader boundary:

1) Reflection

No Format

Principal p = request.getUserPrincipal();
String emailAddress = p.getClass().getMethod("getEmailAddress", null).invoke(p, null);

...

Rather than move the implementing custom classes up, you could define interfaces for your customs classes, and put the interfaces in the common directory. You're code would look like this:

No Format

public interface MyPrincipalInterface extends java.security.Principal {
  public String getEmailAddress();
}

public class MyPrincipal implements MyPrincipalInterface {
...
  public String getEmailAddress() {
    return emailAddress;
  }
}

public class MyServlet implements Servlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    MyPrincipalInterface p = (MyPrincipalInterface)request.getUserPrincipal();
    String emailAddress = p.getEmailAddress();
...
}

...

4) Serializing / Deserializing

...

You

...

might

...

want

...

to

...

try

...

serializing

...

the

...

response

...

of

...

request.getUserPrincipal()

...

and

...

deserialize

...

it

...

to

...

an

...

instance

...

of

...

webapp's MyPrincipal.

How do I get direct access to a Tomcat Realm?

Credit: This code is from a post by Yoav Shapira http https://www.yoavshapira.com/ in the user list

Sometimes access directly into the Tomcat realm object is needed; to do, this the following code can be used. Be aware, however, that by using this, your application is relying on a Tomcat extension and is therefore non-standard.

Note that in order for this to work the Context of the web application in question needs to have its privileged attribute set to "true", otherwise web apps do not have access to the Tomcat classes.

No Format

Server server = ServerFactory.getServer();
//Note, this assumes the Container is "Catalina"
Service service = server.findService("Catalina");
Engine engine = (Engine) service.getContainer();
Host host = (Host) engine.findChild(engine.getDefaultHost());
//Note, this assumes your context is "myContext"
Context context = (Context) host.findChild("myContext");
Realm realm = context.getRealm();

Warning: The above recipe on how to obtain a Context for a web application is a bit obsolete and does not work in Tomcat 7 and later (as Server is no longer a singleton). There are other ways to achieve that. An easy one is to add a Valve or Listener to a context, as those classes have access to Tomcat internals. There may be other ways mentioned in the archives of the users mailing list.

How do I redirect System.out and System.err to my web page?

I have met a situation where I needed to redirect a portion of standard ouput (System.out, STDOUT) and standard error (System.err, STDERR) to my web page instead of a log file. An example of such an application is a compiler research platform that our resarch team is putting online for anybody to be able to quickly compile-test their programs on line. Naturally, the compilers dump some of their stuff to STDERR or STDOUT and they are not web application .jar. Thus, I needed badly these streams related to the compiler output to be redirected to my web editor interface. Having found no easy instructions on how to do that lead me writing up this quick HOWTO. The HOWTO is based on Servlets, but similar arrangements can be done for JSPs. The below example shows the essentials, with most non-essentials removed.

No Format

public class WebEditor
 extends HttpServlet
{
 ...
        public void doGet
        (
                HttpServletRequest poHTTPRequest,
                HttpServletResponse poHTTPResponse
        )
        throws IOException, ServletException
        {
                poHTTPResponse.setContentType("text/html");

                ServletOutputStream out = poHTTPResponse.getOutputStream();

                out.println("<html>");
                out.println("<body>");
                out.println("<head>");
                out.println("<title>WebEditor Test $Revision: 1.6 $</title>");
                out.println("</head>");
                out.println("<body>");
                out.println("<h3>WebEditor Test $Revision: 1.6 $</h3>");
                out.println("<hr />");

                // Backup the streams
                PrintStream oStdOutBackup = System.out;
                PrintStream oStdErrBackup = System.err;

                try {

                  // Redired STDOUT and STDERR to the ServletOutputStream
                  System.setOut(new PrintStream(out));
                  System.setErr(new PrintStream(out));

                  try {
                        // ... call compiler here that produces
                        // tons of STDOUT/STDERR messages ...
                  } catch(Exception e) {
                        out.println(e);
                  }

                } finally {

                  // Restore original STDOUT and STDERR
                  System.setOut(oStdOutBackup);
                  System.setErr(oStdErrBackup);

                }

                out.println("<hr />");
                out.println("</body>");
                out.println("</html>");
        }
}

...

Basically, this works just as described in httphttps://tomcat.apache.org/tomcat-79.0-doc/jndi-resources-howto.html: Within your application, you are using the standard JNDI and JMS API calls. In web.xml (the container independent application descriptor), you specify resource references (stub resources). And in context.xml (the container specific application descriptor), you are actually configuring the JMS connection.

More to the point. Here's some example code, which might be added to a Servlet. The example is sending a message to an MQ server:

No Format

    import javax.jms.Queue;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueSender;
    import javax.jms.QueueSession;
    import javax.jms.Session;
    import javax.jms.TextMessage;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    Context ctx = (Context) new InitialContext().lookup("java:comp/env");
    QueueConnectionFactory qcf = (QueueConnectionFactory) ctx.lookup("jms/MyQCF");
    QueueConnection qc = qcf.createQueueConnection();
    Queue q = (Queue) ctx.lookup("jms/MyQ");
    QueueSession qs = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    TextMessage tm = qs.createTextMessage();
    tm.setText("Hi, there!");
    QueueSender sender = qc.createSender();
    sender.send(tm);
    sender.close();
    qs.close();
    qc.close();

...

  1. I have intentionally omitted proper resource handling. For example, one ought to ensure that qc.close() is always called by using a try { .. } finally { ..} block.

...

  1. The code contains absolutely no references to com.ibm.mq*.jar.

...

  1. There are only two items, which need configuration: "jms/MyQCF", and "jms/MyQ". We'll find them again in web.xml, and context.xml.

We have now written the code. Additionally, our web application needs the following files, and directories:

No Format

    +--META-INF
    |  +--- context.xml
    +--WEB-INF
       +--- web.xml
       +--- lib
            +--- com.ibm.mq.jar
            +--- com.ibm.mqjms.jar
            +--- connector.jar
            +--- dhbcore.jar
            +--- geronimo-j2ee-management_1.0_spec-1.0.jar
            +--- geronimo-jms_1.1_spec-1.0.jar

The application descriptor web.xml looks just the same as usual, with the exception of the following lines:

No Format

  <resource-env-ref>
    <resource-env-ref-name>jms/MyQCF</resource-env-ref-name>
    <resource-env-ref-type>javax.jms.QueueConnectionFactory</resource-env-ref-type>
  </resource-env-ref>

  <resource-env-ref>
    <resource-env-ref-name>jms/MyQ</resource-env-ref-name>
    <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
  </resource-env-ref>

This is simply telling, that the items "jms/MyQCF", and "jms/MyQ" exist, and are instances of QueueConnectionFactory, and Queue, respectively. The actual configuration is in context.xml:

No Format

   <Resource
      name="jms/MyQCF"
      auth="Container"
      type="com.ibm.mq.jms.MQQueueConnectionFactory"
      factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
      description="JMS Queue Connection Factory for sending messages"
      HOST="<mymqserver>"
      PORT="1414"
      CHAN="<mychannel>"
      TRAN="1"
      QMGR="<myqueuemanager>"/>
   <Resource
      name="jms/MyQ"
      auth="Container"
      type="com.ibm.mq.jms.MQQueue"
      factory="com.ibm.mq.jms.MQQueueFactory"
      description="JMS Queue for receiving messages from Dialog"
      QU="<myqueue>"/>

Basically, you just have to enter your values for <myqserver> (the WebSphere MQ servers host name), <mychannel> (the channel name), <myqueuemanager> (the queue manager name), and <myqueue> (the queue name). Both these values, the associated names (HOST, PORT, CHAN, ...), and their collection is truly MQ specific. For example, with ActiveMQ, you typically have a broker URL, and a broker name, rather than HOST, PORT, CHAN, ...

The main thing to know (and the reason why I am writing this, because it took me some hours to find out): How do I know the property names, their meaning, and possible values? Well, there is an excellent manual, called "WebSphere MQ Using Java". It should be easy to find by entering the title into Google. The manual contains a section, called "Administering JMS objects", which describes the objects being configured in JNDI. But the most important part is the subsection on "Properties", which contains all the required details.

How do I use DataSources with Tomcat?

See UsingDataSources

...

See TomcatHibernate

How do I use DataSourceRealms for authentication and authorization?

...