Wednesday, November 23, 2005

Parsing an xml file without having access to the associated DTD

Pfffeww!
I have finally found the solution to my problem...
But lets start from the begin, well somewhat from the beginning.

I needed to change the logfile location as defined in a log4j.xml file from code.
So I started of with a DOM based solution using JDK1.4 features to parse the log4j.xml file, using jaxen to select nodes based on XPath expressions and then updating the found Node with the given value.

But... parsing the log4j.xml file failed because my application could not find the log4j.dtd file.
Removing the log4j.dtd file from the log4j.xml file solved the parsing problem but caused another problem, log4j would not accept the file anymore.
Also setting the validating flag to false did not solve the problem.

After searching the internet and trying several options, I found in the JBoss source code the solution, create inner class anonymous that implements the EntityResolver interface:
EntityResolver resolver = new EntityResolver () {
public InputSource resolveEntity (String publicId, String systemId) {
String empty = "";
ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
System.out.println("resolveEntity:" + publicId + "|" + systemId);
return new InputSource(bais);
}
};
builder.setEntityResolver(resolver);

The returned InputSource consists solely of an empty string, this satisfises loading the dtd, since validation is set to false, the read document is not validated.
Now lets see if is actaully correctly written back to disk.

Tuesday, March 22, 2005

Using JBossPortal RC3

Now that the JBoss organisation has released its 3rd release candidate of JBoss Portal, they are lead in the race for becoming our open source portal provider.

But the requirements for our environment still remain.
We need to connect to a MaxDB database and deploy the portal onto JBoss AS 4.0.2.
So first lets see how I can connect JBpossPortal to a MaxDB database.

Connecting to MaxDB
Reading through the user guide, the steps to deploy JBoss Portal seem fairly simple.
It should be just a matter of creating the database, the database connector file, copying the jboss-portal.sar structure into the deploy directory and starting JBoss.

But obviously it wasn't as simple as that. When starting JBoss I got a NullPointerException:
2005-06-13 13:10:11,709 DEBUG [org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory] Using properties: {user=portal, password=--hidden--}
2005-06-13 13:10:11,709 DEBUG [org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory] Checking driver for URL: jdbc:sapdb://dhu400d.internal.epo.org/portal
2005-06-13 13:10:11,710 DEBUG [org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory] Driver not yet registered for url: jdbc:sapdb://dhu400d.internal.epo.org/portal
2005-06-13 13:10:11,739 DEBUG [org.jboss.resource.connectionmanager.IdleRemover] run: IdleRemover notifying pools, interval: 450000
2005-06-13 13:10:11,782 DEBUG [org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory] Driver already registered for url: jdbc:sapdb://dhu400d.internal.epo.org/portal
2005-06-13 13:10:12,264 INFO [org.hibernate.cfg.SettingsFactory] RDBMS: SAP DB, version: Kernel 7.5.0 Build 018-121-079-776
2005-06-13 13:10:12,264 INFO [org.hibernate.cfg.SettingsFactory] JDBC driver: SAP DB, version: package com.sap.dbtech.jdbc, MaxDB JDBC Driver, MySQL MaxDB, 7.6.0 Build 000-000-003-247
2005-06-13 13:10:12,266 ERROR [org.jboss.portal.core.hibernate.SessionFactoryBinder] Starting failed portal:service=Hibernate
java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:393)
at java.util.Properties.setProperty(Properties.java:102)
at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:106)
at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:1509)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1054)
at org.jboss.portal.core.hibernate.SessionFactoryBinder.createSessionFactory(SessionFactoryBinder.java:261)
at org.jboss.portal.core.hibernate.SessionFactoryBinder.startService(SessionFactoryBinder.java:127)
at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:272)
at org.jboss.system.ServiceMBeanSupport.start(ServiceMBeanSupport.java:173)
at org.jboss.portal.server.util.Service.start(Service.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


This makes working with open source projects so nice, to find out what the problem is, you just have to download the source package, and...

So I downloaded the source package for hibernate, and opened the file org/hibernate/cfg/SettingsFactory.java.
Around line 6 it contains:

if ( props.getProperty( Environment.DIALECT ) == null ) {
props.setProperty( Environment.DIALECT, DIALECTS.getProperty(databaseName) );
}

The constant DIALECTS is a Properties field that contains a mapping between databasenames and SQL dialect class, but it does not contain a mapping for SapDB (or MaxDB for that matter).
The above snippet shows that it is possible to supply the SQL dialect as en environment variable.
So I added -Dhibernate.dialect=org.hibernate.dialect.SAPDBDialect to the JBoss start command, and that did the trick.

Tuesday, February 01, 2005

Deploying jetspeed 2 on JBoss 4.0.1, succeeded!

Finally succeeded with many thanx to Tom Pesendorfer.
He wrote a proper description for J2's wiki.

It all came down to portlet deployment. The portlets can only be deployed after JBoss is started.
According to his description the portlets even need to be undeployed before stopping JBoss, and re-deployed after starting.

Obviously I tried to stop and start JBoss without undeploying the portlets and J2 still worked fine.

In short these are the steps I followed to deploy J2 M1 on JBoss 4.0.1, assuming that a database on MaxDB is already configured:

  1. Copy the default server configuration and name it e.g. jetspeed.

  2. Create a new subdirectory in the directory /jboss-4.0.1/server/jetspeed/lib named j2lib

  3. Copy the sapdb driver jar into that directory

  4. Copy the maxdb datasource descriptor file into the /jboss-4.0.1/server/jetspeed/deploy directory

  5. Open the file /jboss-4.0.1/server/jetspeed/conf/jboss-service.xml

  6. Locate the line that reads <classpath codebase="lib" archives="*">

  7. Add a similar line below it that reads <classpath codebase="lib/j2lib" archives="*">

  8. Copy the jars pluto-1.0.1-rc1.jar, portals-bridges-common-0.1.jar, jetspeed-commons-2.0-M1.jar, jetspeed-api-2.0-M1.jar and portlet-api-1.0.jar into the directory /jboss-4.0.1/server/jetspeed/lib/j2lib

  9. Create the directory /jboss-4.0.1/server/jetspeed/deploy/jetspeed.war

  10. Extract the contents of the file jetspeed.war into that directory

  11. Move the jars commons-logging-1.0.3.jar, log4j-1.2.8.jar, xerces-2.3.0.jar and xml-apis-2.0.2.jar from the directory /jboss-4.0.1/server/jetspeed/deploy/jetspeed.war/WEB-INF/lib into /jboss-4.0.1/server/jetspeed/lib/j2lib

  12. Open the file /jboss-4.0.1/server/jetspeed/deploy/jetspeed.war/WEB-INF/assembly/jetspeed-spring.xml

  13. Locate the bean definition with id 'org.apache.jetspeed.tools.pamanager.servletcontainer.ApplicationServerManager' and comment out the Tomcat version and uncomment the JBoss version.

  14. Start JBoss

  15. Copy all desired portlet war files into the directory /jboss-4.0.1/server/jetspeed/deploy/jetspeed.war/WEB-INF/deploy
    You need at least the file jetspeed-layouts.war.
Now browse to http://localhost:8080/jetspeed and you should see jetspeed up and running.

Thursday, January 20, 2005

Deploying Jetspeed-2 on JBoss 4.0.1, revisited...

My conclusion in my previous post, about the use of UseJBossWebLoader, I appeared to be wrong.
After that all kinds of, less obvious problems, occured.
Like deployment of portlets complaining with ClassNotFound exceptions for classes in their own jar file.
It appeared that after re-enabling that setting again, but removing the commons-logging-1.0.3.jar and log4j-1.2.8.jar files from the directory ../jetspeed.war/WEB-INF/lib, jBoss started without complaining, altough still showing portlets without a body.

The latter is because the JBossManager class, as defined in .../jetspeed.war/WEB-INF/assembly/jetspeed-spring.xml, is not implemented. It only contains stub implementations.

But thats for next time, now its skiing time...

Monday, January 10, 2005

Deploying Jetspeed-2 on JBoss 4.0.1

As stated in one of my previous posts, I need to get Jetspeed 2 running on JBoss 4.0.1 and connected to a MaxDB database.
In the previous post I showed how one can connect J2 to a MaxDB database server.
This post describes the results of my first, failed, attempt to deploy J2 on JBoss using that same MaxDB database.
I am using the M1 binary release package of Jetspeed 2, and most of the steps taken originate from J2,'s wiki.

First I have created a copy of the default jboss server and named it jetspeed.
To keep the jetspeed jar files seperated from JBoss's jars, I created a sub-directory named j2 in the lib directory, and added the following line to the jboss-service.xml:
 <classpath codebase="lib/j2" archives="*"/>
I added a datasource file named jetspeed-maxdb-ds.xml to the deploy directory, to allow jetspeed to connect to my maxdb database server:
<?xml version="1.0" encoding="UTF-8"?>


<!-- The MaxDB database JCA connection factory config for the Jetspeed database -->
<datasources>
<local-tx-datasource>
<jndi-name>/JetspeedDS</jndi-name>
<connection-url>jdbc:sapdb://md80469a.internal.epo.org/j2prod?sqlmode=ORACLE</connection-url>
<driver-class>com.sap.dbtech.jdbc.DriverSapDB</driver-class>
<user-name>j2admin</user-name>
<password>ep0l1ne</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<idle-timeout-minutes>0</idle-timeout-minutes>
</local-tx-datasource>
</datasources>
To be able to use the datasource, the JDBC driver needs to be present on the server's classpath. Therefor I placed the sapdbc-7_6_00_00_3247.jar in the lib/j2 directory.

The binary M1 release contains a directory named shared/lib, I copied all jar files in that directory into the newly created lib/j2 directory.
The binary M1 release also has a directory named jetspeed. This dir contains the extracted contents of the war file.
I copied this directory completely into the deploy directory and renamed it to jetspeed.war.

By default J2 is configured to use the tomcat as application server, to change this into JBoss the file
deploy/jetspeed.war/WEB-INF/assembly/jetspeed-spring.xml
needs to be editted.
So I commented out the
org.apache.jetspeed.tools.pamanager.servletcontainer.ApplicationServerManager
definition for Tomcat and uncommented the definition fo rJBoss.

After that I started JBoss...

The following is the first ERROR that popsup in the server log file:
2005-01-11 09:39:28,291 ERROR [org.apache.commons.modeler.BaseModelMBean] Error creating class org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Class org.apache.commons.logging.impl.Log4JLogger does not implement Log

This might show a potential class loading problem....

In the JBoss docs, chapter 9. Web Applications, I found the following:
UseJBossWebLoader:
This flag indicates that Tomcat should use a JBoss unified class loader as the web application class loader.
The default is true, which means that the classes inside of the WEB-INF/classes and WEB-INF/lib directories of the WAR file are incorporated into the default shared class loader repository described in Chapter 2, The JBoss JMX Microkernel.
This may not be what you want as its contrary to the default servlet class loading model and can result in sharing of classes/resources between web applications.
You can disable this by setting this attribute to false.
Setting this setting to false, solved a lot of the problems. Now J2/JBoss starts fine, but the portlets only show their titlebar and not the contents.

Running Jetspeed-2 using a MaxDB database

My professional goal for 2005 is to base the epoline portal on open source tools only.
The portal server framework is not chosen yet, altough it most likely will become jetspeed 2.
JBoss 4.0.1 will be used as application server, and MaxDB as database management system.

I have just succeeded to run Jetspeed-2 M1 using the MaxDB database.
First you need to setup 2 databases on MaxDB, a production database and a test database, the latter is used during compilation, when executing unit tests.

To allow the jetspeed 2 build process to create the database, you have to create or edit a build.properties file and add the following lines to it:


# -------------------------------------------------------------------------
# configure MaxDB Test DB
# -------------------------------------------------------------------------
org.apache.jetspeed.test.database.default.name=oracle
org.apache.jetspeed.test.database.url=jdbc:sapdb://<db-host>/j2test?sqlmode=ORACLE
org.apache.jetspeed.test.database.driver=com.sap.dbtech.jdbc.DriverSapDB
org.apache.jetspeed.test.database.user=<dba-user>
org.apache.jetspeed.test.database.password=<password>
org.apache.jetspeed.test.jdbc.drivers.path=<path-to>/sapdbc-7_6_00_00_3247.jar

# -------------------------------------------------------------------------
# configure MaxDB Production DB
# -------------------------------------------------------------------------
org.apache.jetspeed.production.database.default.name=oracle
org.apache.jetspeed.production.database.url=jdbc:sapdb://<db-host>/j2prod?sqlmode=ORACLE
org.apache.jetspeed.production.database.driver=com.sap.dbtech.jdbc.DriverSapDB
org.apache.jetspeed.production.database.user=<dba-user>
org.apache.jetspeed.production.database.password=<password>
org.apache.jetspeed.production.jdbc.drivers.path=
<path-to>/sapdbc-7_6_00_00_3247.jar

# -------------------------------------------------------------------------


Now when running maven allClean allBuild, the database will be created on MaxDB.

All we now need to do to access the MaxDB database from j2 running on tomcat, is change the connection settings in ${CATALINA_HOME}/conf/Catalina/localhost/jetspeed.xml.

The JBoss 4 Application Server Guide

The The JBoss 4 Application Server Guide is published for free.
This can be quite usefull during development.