Tuesday, September 25, 2007

Installing Roller 3.1 on WebSphere 5.1 - Part 2

Before going into the null pointer issue we saw at the end of Part 1, I came across couple of more issues, which need to be addressed first.

Roller.tld

This, needs to be defined in the web.xml, with right uri, otherwise, we get this error:
/index.jsp(36,0) File "http://www.rollerweblogger.org/tags" not found

<taglib id="tagLibRef_1">
<taglib-uri>http://www.rollerweblogger.org/tags</taglib-uri>
<taglib-location>/WEB-INF/tlds/roller.tld</taglib-location>
</taglib>

I moved the tld file from classes/META-INF/tlds/ to WEB-INF/tlds/.

LocalTransactionContainment

Whenever I access any roller page, I get the following error:
[9/20/07 15:15:45:536 MDT] 23d768b9 WebAppTransac E WTRN0043I: LocalTransaction rolled-back due to setRollbackOnly.[9/20/07 15:15:45:538 MDT] 23d768b9 WebGroup E SRVE0026E: [Servlet Error]-[LocalTransaction rolled-back due to setRollbackOnly]: com.ibm.ws.LocalTransaction.RolledbackException at com.ibm.ws.LocalTransaction.LocalTranCoordImpl.cleanup(LocalTranCoordImpl.java:1091)

According to the Servlet 2.3 specifications, all transactions should be committed or rolled back within the transaction boundries, in this case, servlet method execution. Now, these could just be select statements also.

One of the solutions to this issue, as described in WebSphere documentation is to edit the ibm-web-ext.xmi file, to include config for each servlet to have either commit or rollback the local transaction. I added this for all the servlets......but, no luck. Keep getting this error.

I then realized that even though, it is printing whole stacktrace, it may not really be the root of errors. So, looking further down, I found this NullPointerException-

RollerRuntimeConfig

So, the null pointers coming all the time is not allowing me to get to the registration page.

javax.servlet.ServletException: ServletException in '/WEB-INF/jsps/tiles/tiles-simplepage.jsp': null

The null pointer indicates that it is getting null for site.name etc. These are given default values in rollerRuntimeConfig.xml file. So, why null? Is that file not read?

There is no error in the logs that this XML file could not be found or failed to load. I had to now look at the roller source code to figure out what's happening. Infact, I put more debug statements in the code to see the values for each of these config parameters.

Well, everything is loaded fine. But, still null pointer when the jsp is looking for these parameters.

Going further deep, it is found that the code, at initialization, reads this xml file, and then stores these properties in the roller_properties table. And when JSP or any other code is getting the values for these, they come from the database.

Ok, lets check the database - roller_properties table. There is only one record, about database.version. No other properties read from XML are in there. That means the database insert is failing? How did it make just one entry though?

No idea, but that was the root cause of all these null pointer exceptions. In order to move forward, I decided to manually enter the default properties in roller_properties table. After adding all the required default properties in the table, I was able to proceed.

Like:
insert into roller_properties values ('site.name', 'roller');

Register First User

Ok, now, I can get beyond the first page. Infact, I can get to the registration page, and register the user. The first user registered will have all admin rights, so, this was really good.
Registration is simple, got it fine. Then, I try to login.....grrr.

Acegi Security

When I login with the registered userid and password, I get this:

Error occurred while invoking error reporter com.ibm.ws.webcontainer.servlet.LoadTargetServletFailure: Failed to load target servlet [FormLoginServlet]

FormLoginServlet, I guess this comes into picture only when Security is enabled in WAS. This is WebSphere specific servlet, and comes into play when login action is sent to j_security.

Looking into login.jsp, it is sending it to j_security_check. Ok, but there is no security enabled in websphere, so, may be that's why it is not finding this servlet. But, I don't want to use WebSphere security. I want to, for now, use simple jdbc authentication so that I can get into roller as admin.

This forced me to look at Acegi security documentation and code. It seemed simple that posting to non j_security_check should call the Acegi filters, rather than calling the app server's FormLoginServlet.

Let's get into security.xml, and make sure jdbcAuthenticationDao bean has right property value set for jndiName.
Next, look at authenticationProcessingFilter bean in same security.xml and update the property value from j_security_check to something else, I chose a_j_s for testing.
Now, go to login.jsp, and change the action to go to a_j_s instead of j_security_check.

Recycle the server. And wow...... I can login now!

Couple of more things:
rollerProperties.jsp - it uses JSTL 1.1 URI, so change it to use JSTL 1.0 URI, as we did in taglibs.jsp.
Also, roller.properties file has upload and search index directories defned, make sure they have trailing slash, otherwise it will give - can't access directory error.

Great.... now I am able to create the first blog.

I am still getting transaction rolledback exception, but only initially, it must be coming out of Acegi code, as it uses Spring, and since that code is executed very minimal after you are authenticated and authorized, the error doesn't show up every time you do something. But still, the error/warning is present in the logs, without causing any known harm.

Monday, September 24, 2007

Installing Roller 3.1 on WebSphere 5.1 - Part1

Roller weblogger, what I thought would be a simple installation, turned out to be a painful one. I am trying to put together some of the major issues I came across and how I fixed them. Partly to blame roller community here, no good documentation, hopefully this will help some of the users getting Roller working on WebSphere, specially, version 5.1.x, AIX 5.3.

The Database


So, I started with database. I am using DB2 version 8.2. The OS is AIX 5.3.
When I tried Roller more than a year ago, it did not have db2 scripts, but thankfully, they have it now. It was easy. But, I was installing in an existing database, so added a separate tablespace for roller tables, and updated the scripts to create tables in the new tablespace.
Everything worked fine on DB side.

Datasource

Since I will be using Type 4 driver, created a datasource in the WebSphere with jndi name jdbc/rollerdb. Verified the connection, all good.

The WAR file

As documented in the installation guide the war file needs to be updated with hibernate and related jar files. Got all that, and put them in WAR's lib directory. I did not add db2 driver libraries, because WebSphere has them all, and I will be using type4 driver configured in websphere.

Updated the following config files:
hibernate.xml - use DB2Dialect
log4j.properties - specify the location of the log file on the server.
roller.properties - updated the upload and cache directory paths. I chose /tmp to start with.
Remove the <dispatcher> tags from filter section in web.xml, as documented there. This is because WAS 5.1 is servlet 2.3.

Yes, roller documentation says not to update roller.properties file directly, but define a new one, and specify it in JVM settings. Well, test installation, and doesn't matter anyway.

Just to be clear, WAS 5.1 is:
Servlet 2.3,
JSP 1.2 and
JSTL 1.0
(J2EE 1.3)

I thought it is all set now, and will be so easy to install on WebSphere, as it was on Tomcat.

Installation

I am deploying the roller in an existing app server in my dev system. Nothing special in that app server, just some other ear files are installed and working great.
Install the roller.war file, providing the context root as roller. Most of the installation takes default settings. And, fnally, see the message - roller_war.ear installed successfully. So far so good.

Recycle the app server. And there is goes:
Module, roller.war, of application, roller_war.ear/deployments/roller_war, fa
iled to start


That's it. No more information. No logs, nothing. Looking around on the web... not much information either. Somewhere I saw the problem could be with listeners denined in roller.tld file. The location of tld is also beyond my understanding. It is in ....WEB-INF/classes/META-INF/tlds/
Open it and I see:

<listener>
<listener-class>org.apache.roller.ui.core.RollerSession></listener-class>
</listener>
<listener>
<listener-class>org.apache.roller.ui.core.RollerContext</listener-class>
</listener>

Removed both of these from the tld. I don't know why they are defined here, they exist in web.xml also, where they should be.

Ok, start it again and see what happens now. Well, the application appear to do something more this time. Little better, got to see some errors in the logs now.

HibernateRoll F org.apache.roller.business.hibernate.HibernateRollerImpl TRAS0014I: The following excep
tion was logged java.lang.VerifyError: (class: org/apache/roller/business/hibernate/HibernatePersistenceStrategy, method: signature:
(Ljava/lang/String;Ljava/lang/String;)V) Incompatible argument to method


Ok, this means that the method being called has different arguments than what's being passed to it. Appeared to me that there might be two different versions of a class file in two different jars, and one, the old one is getting loaded first. Checked some obvious jars, found nothing suspicious. Let's fix the logging first.

Logging


I really wanted the log4j for roller working, so that I get the clue on what it is doing. So far, it was not creating the log file. Based on past experience with log4j, Apache commons-logging and WebSphere, I did this:
Add to web.xml:

<context-param id="ContextParam_id1">
<param-name>/log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties></param-value>
</context-param>

Got to see my roller.log now :-)

Classloader issue?

Well, having worked with WebSphere and dealt with its nasty classloaders since version 3.x, I thought, lets try to change the classloader policy.
So, the webapp's classloader policy is now set to PARENT_LAST. I did not want to do this, but nothing else was working.
Ok, start it again, somewhat better.

The VerifyError on Hibernate has gone now. Strange, I am not sure what it was conflicting with in parent.

And, now, it comes with new problems, of course, classloader mode has changed, so you will have new problems.

java.lang.LinkageError: Class org/xml/sax/EntityResolver violates loader constraints: definition mismatch between parent and child loaders
at org.jdom.input.SAXBuilder.configureParser(SAXBuilder.java:608)

The xmlrpc-1.2-b1.jar

There is org/xml/sax class files in this jar, which come with Java 1.4.2 also. easily tells you what the problem is. I removed all org/xml/sax class files from this jar keeping rest of them there.

Recycle... let's see what happens now!

New error:
Could not find datasource: jdbc/rollerdb
java.lang.ClassCastException: com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource

The jdbc2.0_ext.jar

This problem I have seen many times, Easy, just delete this jar from WEB-INF/lib/. This is because websphere already has javax.sql.*.

Ok, another recycle. See what it has got now:

Could not obtain connection metadata
java.sql.SQLException: null userid not supportedDSRA0010E: SQL State = null, Error Code = -99,999DSRA0010E: SQL State = null, Error Code = -
99,999
at com.ibm.db2.jcc.c.b.E(b.java:1975)
at com.ibm.db2.jcc.c.b.a(b.java:1981)

Ok, seen this before. That's my datasource. Need to use right authentication settings for container managed authentication. Fixed it, recycled it.

Cool...... it started successfully. Very good. Lots of initializing messages. no errors. Let's see if we can access it now?

JSTL 1.0

Nope, JSTL errors. Can't find the JSTL tags. I had dealt with this issue also in one of my other apps. Basically, the JSPs are using JSTL 1.1, but WebSphere 5.1 will support 1.0 version only.

Ok, locate the file giving error, /taglibs.jsp. Replace the taglib uris-
http://java.sun.com/jsp/jstl/core
with
http://java.sun.com/jstl/core

and

http://java.sun.com/jsp/jstl/fmt
with
http://java.sun.com/jstl/fmt

And, replace the two jar files, standard.jar and jstl.jar with their 1.0 versions.

Recycle, lets see if it is any better.......

Nope..... ugly null pointer.

RollerRuntimeConfig:getProperty - Trouble accessing property: site.shortName
java.lang.NullPointerException
at org.apache.roller.config.RollerRuntimeConfig.getProperty(RollerRuntimeConfig.java:67)
at org.apache.jsp._tiles_2D_simplepage._jspService(_tiles_2D_simplepage.java:277)
at com.ibm.ws.webcontainer.jsp.runtime.HttpJspBase.service(HttpJspBase.java:89)

Rest, we deal in part 2.