Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Tuesday, February 3, 2009

Configuring JDBC Datasource in Tomcat 5.0.28 in Eclipse WTP

I use Eclipse WTP for developing Web applications. In my previous post I mentioned that I changed the Database connection pool to use the Weblogic connection pool. The configuration in Weblogic was straightforward and simple, but it posed an issue for me during development because I was not able to configure the Datasource in the Installed Server Runtime in my Eclipse WTP. Either I had to use Reflection to supply the class and modify it between Environment deployments and local deployments or needed to fix the issue with Tomcat Datasource. The error that I was constantly getting was


ERROR DatabaseManager.getConnection - org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:780)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
at com.pepsi.bdb.connections.DatabaseManager.getConnection(DatabaseManager.java:36)


Googling the error wasn't very fruitful because it mostly dealt with configuring Datasource in Tomcat directly, but not much information was available on configuring with Eclipse WTP. Also, there were several ways of configuring it mentioned in Serverside website and none seem to work for me. Finally I figured it out today and here is how I did

In Eclipse WTP, expand the configured Server under Servers, you will see a file server.xml. This is a copy of the server.xml file that Eclipse creates for you, but uses the libs from the Tomcat folder you configured. In this file add your Datasource under the tag <GlobalNamingResources> as shown below:


<GlobalNamingResources>
<Environment name="simpleValue" type="java.lang.Integer" value="30"/>
<Resource auth="Container" description="User database that can be updated and saved" name="UserDatabase" type="org.apache.catalina.UserDatabase"/>
<Resource name="myDbPool" type="javax.sql.DataSource"/>
<ResourceParams name="UserDatabase">
<parameter>
<name>factory</name>
<value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
</parameter>
<parameter>
<name>pathname</name>
<value>conf/tomcat-users.xml</value>
</parameter>
</ResourceParams>
<ResourceParams name="myDbPool">
<parameter>
<name>validationQuery</name>
<value>select * from dual</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>4</value>
</parameter>
<parameter>
<name>password</name>
<value>(password)</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:oracle:thin:@(servername):(portNum):(SID)</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>oracle.jdbc.driver.OracleDriver</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>2</value>
</parameter>
<parameter>
<name>username</name>
<value>(username)</value>
</parameter>
</ResourceParams>
</GlobalNamingResources>


Go to the folder where your server is actually located and place the jar file ojdbc14.jar (for Java 1.4, for lower versions, uses classes12.jar) in the folder %TOMCAT_HOME%\common\lib.

In the server.xml on the Eclipse, place an entry inside the <Context> element of your application that is inside the <Host> element as below:


<Context docBase="myApp" path="/myApp" reloadable="true" source="org.eclipse.jst.j2ee.server:myApp">
<ResourceLink name="myDbPool" global="myDbPool" type="javax.sql.DataSource"/>
</Context>


That is it. This did the trick for me. For the web.xml entry inside your web application and Java code, refer to my previous post.

Thursday, January 22, 2009

Configuring JDBC Datasource in Weblogic and using it in the code in a web application

I decided to leverage the Connection pooling features provided by Weblogic in one of the web applications that I wrote. This application uses plain JDBC since dome dynamic capabilities are required for sql statements and so we decided against Hibernate/Spring. Initially the code was written against Open source Snaq DB Connection pooling. Apparently, Weblogic has very good connection pooling features that an application can leverage. Since the code was object oriented and all DAO classes used a DBManager class to get their connection, all I needed to change was a method.

The Weblogic documentation shows how to configure a Data source on Weblogic but has little mention on how to get it working from your web application. The following details should help you set it up. To configure a Data source check the following Weblogic documentation.
http://edocs.bea.com/wls/docs90/jdbc_admin/jdbc_datasources.html.
In the Data source, I am assuming that you configured the JNDI name as "myAppDbPool"

In your web application, you will need a web.xml entry and an entry in a new file weblogic.xml.

The web.xml entry looks like below


<resource-ref>
<res-ref-name>myAppDbPool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>


If you don't have a weblogic.xml file in your app create one. It goes in your WEB-INF beside web.xml file. The weblogic.xml file looks like below

<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN"

"http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">

<weblogic-web-app>

<reference-descriptor>
<resource-description>
<res-ref-name>myAppDbPool</res-ref-name>
<jndi-name>myAppDbPool</jndi-name>
</resource-description>
</reference-descriptor>

</weblogic-web-app>


That's the configuration part. Now all you need to do is code your web application to retreive the Database connection from this Datasource. I made the DBManager class singleton to make sure only one instance runs at a given time. The DBManager class method looks like below:

public Connection getConnection() throws Exception
{
InitialContext ctx=new InitialContext();
DataSource ds=(DataSource)ctx.lookup("java:comp/env/myAppDbPool");
Connection connection=ds.getConnection();
return connection;
}


That's it. Use this connection in your DAO and you are all set. But make sure that your DAO object calls connection.close() when it is done accessing the data. According to Weblogic documentation, this returns the connection to the pool for other objects to access it.

If you have better approach or you see any flaws in this, let me know in the comments.

Friday, January 9, 2009

Errors when using Struts 1.3.x that are not intuitive javax.servlet.ServletException: org/apache/commons/lang/UnhandledException

Today, I decided to upgrade a new application that I was working on to Struts 1.3.10. After getting the necessary jars and stuff from the struts-blank.war, and upgrading my webapp library with those, everything was fine until I ran into this error. Apparently, Struts 1.3.x removed some jars from the distribution, and the dependecies had to be resolved externally. The error gave me no clue that it was unable to find the commons-lang.jar. After struggling with it for sometime, I finally figured out that the commons-lang.jar was the missing jar. Usually when a jar is missing we get a NoClassDefFoundError that points in the right way, but the error trace for this gave no clue at all. Anyways if you happen to run into this error the key is to have the commons-lang.jar in your classpath from this location Apache Commons


2009-01-09 17:30:34,001 ERROR InsertTag$InsertHandler.doEndTag - ServletException in '/pages-bdb/batchListDetail.jsp': org/apache/commons/lang/UnhandledException
javax.servlet.ServletException: org/apache/commons/lang/UnhandledException
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:244)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:704)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:590)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:510)
at org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:966)
at org.apache.jasper.runtime.PageContextImpl.doInclude(PageContextImpl.java:610)
at org.apache.jasper.runtime.PageContextImpl.include(PageContextImpl.java:604)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.apache.struts.tiles.TilesUtilImpl.doInclude(TilesUtilImpl.java:129)
at org.apache.struts.tiles.TilesUtil.doInclude(TilesUtil.java:152)
at org.apache.struts.tiles.taglib.InsertTag.doInclude(InsertTag.java:764)
at org.apache.struts.tiles.taglib.InsertTag$InsertHandler.doEndTag(InsertTag.java:896)
at org.apache.struts.tiles.taglib.InsertTag.doEndTag(InsertTag.java:465)
at org.apache.jsp.pages.shared.template_jsp._jspx_meth_tiles_insert_2(template_jsp.java:173)
at org.apache.jsp.pages.shared.template_jsp._jspService(template_jsp.java:92)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:704)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:474)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:409)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1083)
at org.apache.struts.tiles.TilesRequestProcessor.doForward(TilesRequestProcessor.java:295)
at org.apache.struts.tiles.TilesRequestProcessor.processTilesDefinition(TilesRequestProcessor.java:271)
at org.apache.struts.tiles.TilesRequestProcessor.processForwardConfig(TilesRequestProcessor.java:332)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:232)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:534)

Thursday, August 7, 2008

Log4j writing to a dynamic log file for every run

In my recent project, I was using Log4J and I had a requirement where I had to write to a new dynamic log file every time and the name of the log file was determined at runtime. In specific terms each run would produce a Project and the log file had to reflect the project name. Since this project name could be repeated across runs, the timestamp needed to be added to the log file. I searched across Google and didn't find much help in this regard. So I decided to post the code I wrote.

I didn't want to lose setting the log levels from the log4j.xml file and wanted all the options I could configure for the FileAppender except the file name. The file name was configured too, but the code had to overwrite and create a new file at runtime. Here is the code..



Date projDate = new Date(Long.parseLong(project.getTimeStamp()));
StringBuffer dateStr = new StringBuffer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
dateStr = sdf.format(projDate, dateStr, new FieldPosition(0));
String logFileName = logsDir + File.separator + project.getName() + "_" + dateStr.toString() + ".log";
log.info("\n**************Log file for this run: " + logFileName + "\n**************\n");

Logger rootLogger = Logger.getRootLogger();
Enumeration appenders = rootLogger.getAllAppenders();
FileAppender fa = null;
while(appenders.hasMoreElements())
{
Appender currAppender = (Appender) appenders.nextElement();
if(currAppender instanceof FileAppender)
{
fa = (FileAppender) currAppender;
}
}
if(fa != null)
{
fa.setFile(logFileName);
fa.activateOptions();
}
else
{
log.info("No File Appender found");
}



That's it. The logs were created for each and parallel runs would write to different files...

Wednesday, July 16, 2008

Java: Loading an XML file from the CLASSPATH

Today, I faced this issue in Java coding. I needed to load an XML file which was in my classpath but not in the same directory as the classes. The deliverable was a jar and the properties and the configuration XML files were in a different folder and were appended to the classpath at the runtime. The issue was that the file could not be located through the the statement


String fileName = getClass.getSystemResource("config.xml").getFile;


Then I thought that it checks relative to the current class and so used the statement


String fileName = ClassLoader.getSystemResource("config.xml").getFile;


But then, it wouldn't still recognize the file. The reason is the same, it checks relative to the classes folder. I did not want to get the classpath from the system and browse through it for the config file since the class path could get larger. A couple of google searches and a little research later, I found the solution. The workaround is by using the following statement


String fileName = Thread.currentThread().getContextClassLoader().getResource("config.xml").getFile;


It only makes sense since in the above statement, you get hold of the context class loader and find the path in the entire classpath...