Showing posts with label servlets. Show all posts
Showing posts with label servlets. Show all posts

June 30, 2010

Initializing MyBatis on Application Startup using a ServletContextListener

In order to initialize MyBatis 3.0.1 and make it available to your java web application your can use a ServletContextListener to set the sqlSessionFactory as an application context attribute.

This way all your servlets will have access to this object once the web application is up. So here's how to do it.

1) Configuring the custom ServletContextListener

Add the listener definition to the web deployment descriptor (web.xml)

<listener>
  <listener-class>
com.mypackage.listeners.CustomServletContextListener
  </listener-class>
</listener>

Implement the listener

 
package com.mypackage.listeners;

import java.io.Reader;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class CustomServletContextListener implements ServletContextListener
{
 public void contextInitialized(ServletContextEvent event) 
 {   
  ServletContext ctx = event.getServletContext();  
       
     String resource = "mybatis.config.xml";
     try{
      //load mybatis configuration 
      Reader reader = Resources.getResourceAsReader(resource);      
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
      ctx.setAttribute("sqlSessionFactory", sqlSessionFactory);
     }
     catch(Exception e){
      System.out.println("FATAL ERROR: myBatis could not be initialized");
      System.exit(1);
     }     
 }

 @Override
 public void contextDestroyed(ServletContextEvent event){
  
 }
}

2) Retrieving the sqlSessionFactory from a Servlet

Now whenever you need a myBatis sqlSessionFactory, you can use the following code from any servlet

 

public class TestServlet extends HttpServlet{
      
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
  {
   SqlSessionFactory sf = (SqlSessionFactory)getServletContext().getAttribute("sqlSessionFactory");
   MyCrazyDAO dao = new MyCarzyDAO(sf); //you can use the sqlSessionFactory to initialize your dao layer
   
   try{
    dao.getSomeDataFromDB();
    request.setAttribute("abc", abc);         
   }
   catch(PersistenceException p){
    p.printStackTrace();  
   }
          
   RequestDispatcher view = request.getRequestDispatcher("page.jsp");
   view.forward(request, response); 
  }
}


Initializing multiple MyBatis environments/databases on application startup

If you have multiple databases (eg. defined multiple <environment> elements) in your mybatis.config.xml file (as shown below), you will need a minor change.

<environments default="development">
  
  <environment id="development">
   <transactionManager type="JDBC"/>
   <dataSource type="JNDI">
    <property name="initial_context" value="java:comp/env"/>
    <property name="data_source" value="/jdbc/mydb"/> 
   </dataSource>
  </environment>
  
  <environment id="testing">
   <transactionManager type="JDBC"/>
   <dataSource type="POOLED">
    <property name="driver" value="${db.driver}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" value="${db.pass}"/>
   </dataSource>
  </environment>
  
 </environments>

The MyBatis reference says that you should use only one SqlSessionFactory instance per database.

Therefore the code ServletContextListener from before should be modified to create two independent sqlSessionFactory variables in application scope.

try{
      //load mybatis configuration 
      Reader reader = Resources.getResourceAsReader(resource);      
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //will associate the session factory with the 'default' environment
      ctx.setAttribute("sqlSessionFactory", sqlSessionFactory);
      SqlSessionFactory sqlSessionFactory2 = new SqlSessionFactoryBuilder().build(reader,"testing");
      ctx.setAttribute("sqlSessionFactory2", sqlSessionFactory2);
     }
     catch(Exception e){
      System.out.println("FATAL ERROR: myBatis could not be initialized");
      System.exit(1);
     }  

You can now use two sqlSessionFactories to manipulate data from two databases. And you can reference them in any servlet using

SqlSessionFactory sf = (SqlSessionFactory)getServletContext().getAttribute("sqlSessionFactory");
SqlSessionFactory sf2 = (SqlSessionFactory)getServletContext().getAttribute("sqlSessionFactory2");

May 2, 2010

Setting up Log4j for simple Java Web Applications + Tomcat 5/6

If you have developed Java based web applications you probably felt the need at some point to use log4j for better more efficient logging.

There are different ways to setup log4j for you web application. Here I will present 2 of ways to setup log4j, particularly aimed at simple java web applications (eg. plain servlets/jsp webapps).

First you can download the following basic log4j.properties file. Just replace <appname> with your application name (eg. FunkyWebApp).


log4j.logger.<appname>logger=DEBUG, C, fileappender

log4j.additivity.<appname>logger=false
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.layout=org.apache.log4j.PatternLayout
#basic pattern
log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m %n
#advanced pattern (slow)
#log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m - in %M() at line %L of class %C %n 

log4j.appender.fileappender=org.apache.log4j.RollingFileAppender
log4j.appender.fileappender.File=${appRootPath}WEB-INF/logs/<appname>.log
log4j.appender.fileappender.MaxFileSize=500KB

## Keep one backup file
log4j.appender.fileappender.MaxBackupIndex=3
log4j.appender.fileappender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileappender.layout.ConversionPattern=%p %t %c - %m%n
#log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m %n

Now use one of the methods below to add and enable Log4J in your web application

Method 1: Use Servlet to initialize log4j

Step 1: Put log4j.properties file in the right place

  • Place 'log4j.properties' into the root of your classpath. See an example web application layout here

    Tip: when web application is deployed it should be in /WEB-INF/classes/log4j.properties.

  • If using eclipse place 'log4j.properties' under your project_name/src directory

Step 2: Define the servlet mapping in web.xml

Add the following code to WEB-INF/web.xml

<servlet> 
     <servlet-name>log4j-init</servlet-name>
     <servlet-class>com.FunkyWebapp.servlets.Log4jInit</servlet-class> 
     <init-param>
       <param-name>log4j-init-file</param-name>
       <param-value>WEB-INF/classes/log4j.properties</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
</servlet> 

Make sure to change the java class file path to be relevant to your project. 'com.FunkyWebapp.servlets.Log4jInit'

Step 3: Add the servlet you mapped in Step 2 to your application

Add the following servlet to your project


import javax.servlet.http.HttpServlet;
import org.apache.log4j.PropertyConfigurator;

public class Log4jInit extends HttpServlet {

 public void init()
 {
     String prefix =  getServletContext().getRealPath("/");
     String file = getInitParameter("log4j-init-file");
 
     // if the log4j-init-file context parameter is not set, then no point in trying
     if(file != null){
      PropertyConfigurator.configure(prefix+file);
      System.out.println("Log4J Logging started: " + prefix+file);
     }
     else{
      System.out.println("Log4J Is not configured for your Application: " + prefix + file);
     }     
 }
}

Make sure the <servlet-class> element in Step 2 matches the fully qualified name of your servlet. And make sure it's in the right package.

Step 4: Initialize the logger and start logging from other servlets in your web application


public class MyServlet extends HttpServlet {
...
private Logger log = Logger.getLogger("<appname>logger");
.
.
.
log.debug("Some string to print out");

}

Make sure the <appname> part matches with the line

log4j.logger.<appname>logger in the log4j.properties file

Notes:
When you initialize log4j in a servlet you will only be able to log from classes which are loaded after the servlet (eg. other servlets). You won't be able to do logging from a ServletContextListener for example.

Method 2: Initialize log4j in a ServletContextListener

Step 1: Put properties file in the right place

  • Place 'log4j.properties' into the root of your classpath. See an example web application layout here

    Tip: when web application is deployed it should be in /WEB-INF/classes/log4j.properties.

  • If using eclipse place 'log4j.properties' under your project_name/src directory

Step 2: Define a listener mapping in web.xml

Add the following servlet listener mapping in web.xml:


<listener>
  <listener-class>
   com.package.listeners.ApplicationServletContextListener
  </listener-class>
</listener>

Step 3: Add the SerlvetContextListener class to the application

public class ApplicationServletContextListener implements ServletContextListener
{
 public void contextInitialized(ServletContextEvent event) 
 { 
     ServletContext ctx = e.getServletContext();
   
  String prefix =  ctx.getRealPath("/");     
  String file = "WEB-INF"+System.getProperty("file.separator")+"classes"+System.getProperty("file.separator")+"log4j.properties";
          
     if(file != null) {
       PropertyConfigurator.configure(prefix+file);
       System.out.println("Log4J Logging started for application: " + prefix+file);
     }
     else
     {
      System.out.println("Log4J Is not configured for application Application: " + prefix+file);
     } 
       
     
 }

 public void contextDestroyed(ServletContextEvent event) 
 {
  
 }

}

Step 4: Define the logger and start logging from other servlets in your applications


public class MyServlet extends HttpServlet {
...
private Logger log = Logger.getLogger("<appname>logger");
.
.
.
log.debug("Some string to print out");

}

Notes:

  • Easier to implement that Method 1
  • All web application now has access to log4j (including listeners)
  • Placing log4j initialization in a ServletContextListener allows initialization of log4j when your web application is loaded for the first time.

Other resources about log4j

Log4j, configuring a Web App to use a relative path.

April 8, 2010

The evolution of Servlets and JSP

This article is about clarifying how to use Servlets and JSP pages. When starting out to learn Java Web Application development you will undoubtedly have many questions about how all the terms and terminology interacts with each-other, or what the benefit is. Eg. Scriptlets, Servlets, Tags, Expression Language, Standard Actions, Custom Tags, Directives, etc

If you didn't have the good fortune to stumble upon a good book to give you a clear and solid foundation you will often be confused about when to use what etc.

So here is a simple introduction to why the basic Java Web Application Development technologies were built.

In the beginning

In the beginning there was darkness (and simplicity). The only things that existed were static html pages. They would have html and text, and that's it.

Soon after came dynamic pages, which could show things like the current date or timestamp. The server would generate the html code, and everyone was happy (see Perl and CGI scripts)

Servlets

After Java emerged, Servlets were created to allow dynamic pages to be written using the Java language.


public class NiceServlet extends HttpServlet
{ 
 protected void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  
   PrintWriter out = response.getWriter(); 
   out.println("<html><head><title>A Nice Servlet</title></head><body>"); 
   out.println("The nice body of this servlet displays the date for you: "+(new java.util.Date())); 
   out.println("</body></html>"); 
   out.close(); 
 } 
}

]]>

For a time things were good, as Servlets could leverage the power of Java to create just about any kind of html content.

  • Advantages:Now you can generate dynamic html with Java.
  • Disadvantages: Very hard to maintain and cumbersome to write and update once the dynamic page starts to have a lot of stuff.

But things became complicated, because creating large dynamic html page content with lots of data required many lines of out.println() statements. So something else came along...

Scriptlets and Expressions


<% scriptlets %>

<%= expressions %>

Scriptlets and Expressions were created to simplify the generation of code from a page. With the creation of JSP pages, you could now write a scriptlet or expression and the Servlet Container (eg. Tomcat) would dynamically generate all the servlet code for you automatically (eg. all the out.println() statements).

There were other things as well that simplified things. Directives, declarations and of course server side comments.


<%@ directives %> //include other files or import java packages

<%! declarations %> //declare variables or methods outside of the service() method

<%-- comments --%> 

  • Advantages:You can do anything with Scriptlets and Expressions that you can write with Java code.
  • Disadvantages: A lot of custom code which makes the JSP page hard to maintain and read.

Standard Actions

To simplify things even more, now you didn't even have to use Scriptlets or Expressions, you could use Standard Actions

Why, because JSP pages started to get large and bogged down with Scriptlets, Expressions all over the place. It was hard to maintain (less by a Java developer) but mostly by web designers. Or at least that was the drive to simplify things (I still think today if you're developing Java web applications you need to be familiar with both HTML and Java equally);

The getProperty Standard Action in Action. The following code will display the name property of the bean called 'user' (if it's defined);
<jsp:getProperty name="user" property="name" />
The above standard action will allow the Servlet Container to convert the code to the following (which you otherwise would have had to write)
User user = (User)request.getAttribute("user");
out.println(user.getName());

But Standard Actions had a shortcoming. They weren't compatible with indexed properties. So having a Garden object which had a Tree object which had a getName() property would be a problem as you couldn't do this:

<jsp:getProperty name="garden" property="tree.name" />

Standard Actions would also do silly things like throw a Null pointer exception if the property didn't exist or was 'null'

  • Advantages: Much more cleaner and quicker to use than scriptlets and expressions
  • Disadvantages: Don't work with anything except String or primitive bean properties

EL (JSP Expression Language)

So came EL (JSP Expression Language) which allows you to do all of the above (introduced with JSP 2.0 Specification)

I'm not going to go into detail here about how the EL is used and what it does, but rest assured it's cool, once you digg it that is. I'll leave it up to others to get into it, but here's a useful link if you don't know anything about EL A JSTL Primer Part 1 - The Expression Language.

  • Advantages: Much easier to use. Empty or null values don't throw errors.
  • Disadvantages: No easy way to loop through collections or arrays.

Unfortunately though even EL has its shortcoming. It can't for one thing loop through collections or arrays.

JSTL (Java Standard Tag Library)

JSTL are custom tags which let you do things like formatting data or iterating through collections and displaying each element in a table row for example.

JSTL Tags can be used as easily as JSP standard actions. That's one advantage.

The main advantage however is that JSTL combined with EL will cover 99% of the things you will need in a JSP file.

Custom Tag Libraries

Finally, for those .1% of cases where you need some complex behavior specific to your application, you can also create your own custom tags. But that is quite an advanced topic, if any of the previous things I mentioned in this post aren't too familiar to you

If you are looking just for some custom tags, here is a good website with various libraries. JSP Tag Libraries.

So that's a quick run through the basic evolution of Servlets and JSPs. I hope you found this article useful. Please let me know if you did.