Thursday, May 10, 2007

Naming conventions

Naming conventions are a good thing, there's no doubt abou that.

But its usually quite difficult to establish a proper naming convention, so its far eassier to use an existing naming convention that can be ammended if needed. On java.net a project exists that establishes such a naming convention for J2EE projects, very handy!

Friday, April 20, 2007

Using JConsole

I updated my eclipse to version 3.2.2, lucky me did not remove the previous version just yet, and run into a crashing system that seems to run out of memory. So I decided to connect jconsole to eclipse to view its memory consumption.
To do so I needed to start eclipse using JDK 5, with the system property -Dcom.sun.management.jmxremote.
Now JConsole is able to connect to the eclipse process and show its memory consumption.

After playing a while with eclipse the OOM exception hapened again, but saidly JConsole has lost its connection, so nothing to see what/.where had happened.

The story continues...

Tuesday, April 03, 2007

Mocking a base class

The next problem that arose when trying to unit test my portlet, is that my portlet implementation calls some methods of its base class, javax.portlet.GenericPortlet. How can these method calls be mocked?

In the unit test implementation an inner class is defined that extends the class under test.
This inner class can then mock any base class method called from the class under test:
public class MyPortletTest extends TestCase {

private PortletContext portletContext = EasyMock.createMock(PortletContext.class);

protected void setUp() throws Exception {
super.setUp();

// Use the inner class derived from the actual CUT that provides
// overrides for the base class methods.
testObject = new TestObject();
}

// Additional methods removed for clarity...

/**
* Need to extend the portlet under test for overriding base class methods.
*/
private class TestObject extends MetaInfoPortlet {

/**
* A mock needs to be returned
*/
@Override
public PortletContext getPortletContext() {
return portletContext;
}
}
}
Using this scheme one can override any of the base classes methods used in the class under test (CUT), and provide a mock based implementation.

Thursday, March 29, 2007

EasyMock and IllegalStateException

When writing a portlet and trying to unit test it, you definitly need somekind of mock implementation. I chose to use EasyMock 2.2 for that purpose because I think its easier to use. I will not explain nor defend this decision.

I have been using EasyMock for some time now, and every now and then I stumble over the problem IllegalStateException problem. Sometimes this is caused by not having 'replay'ed the mocks, but now its different. The stack look s like this:
java.lang.IllegalStateException: 2 matchers expected, 1 recorded.
at org.easymock.internal.ExpectedInvocation.createMissingMatchers(ExpectedInvocation.java:41)
at org.easymock.internal.ExpectedInvocation.(ExpectedInvocation.java:33)
at org.easymock.internal.ExpectedInvocation.(ExpectedInvocation.java:26)
at org.easymock.internal.RecordState.invoke(RecordState.java:64)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:24)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:45)
This exception is thrown when executing request.setAttribute(MetaInfoPortlet.BEAN_ATTR, EasyMock.anyObject());.

So why is this excpetion being thrown at me? The message gives a hint, 2 matchers expected, recorded 1. So it lacks a matcher...

If I now change the code to request.setAttribute(EasyMock.matches(MetaInfoPortlet.BEAN_ATTR), EasyMock.anyObject());, it works fine. Now why is this? If I change the code to request.setAttribute(MetaInfoPortlet.BEAN_ATTR, "something");, it works as well, but now I get the following:
java.lang.AssertionError:
Unexpected method call setAttribute("bean", {test=Let's see if this tst value comes through?}):
setAttribute("bean", "something"): expected: 1, actual: 0
So it looks like the you either have to supply your mock with fixed values or you have to supply it with matchers, as it says in EasyMocks documentation: "If you would like to use matchers in a call, you have to specify matchers for all
arguments of the method call.
"

Bottom line: read the documentation.

Wednesday, March 21, 2007

JSTL and JSP Expression Language used in JSP 2.0

The release of the JSP 2.0 and servlet 2.4 specification has changed the way expressions are used within JSP pages.
From now on you can use expressions throughout the whole JSP page.
There appeared to be some limitations though, when mixing expressions with tags, you can only use expressions within tag attribute values.
So name is ${your.name}. is perfectly legal, as well as href="${link.url}" />But ${attrName} is not.

When trying to figure this out, I stumbled over several issues before I got the desired output. First you must declare your application as a 2.4 webapp using the following declaration:

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
version="2.4" />


When using the JSTL taglibrary, you must be aware that the taglib url is different, jsp is added prior to jstl within the URL.

For 2.3 webapps you should use taglib <%@taglib uri="http://java.sun.com/jstl/core" prefix="c"%> while for 2.4 webapps you use <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> />

Using Performancing when blogging

Today I figured out how the performancing firefox extension must be configured, so this will be the very first post I do from firefox.

I think this can become a very handy tool that eases posting to my blog!

Some interesting features are the use of a rich text editor.

See ya next time.

Thursday, November 30, 2006

JCR Portlet demo

Its been a long time, I know. But now I am back again.

Currently I am working on a demo for connecting a portlet application to a JCR repository.
The portlet application consists of 2 portlets, one show a table of contents, and the other shows the selected content item.
The first problem I stumble into after creating a web project using maven 2, was that the war file created contained the portlet-api.jar causing a ClassCastException in pluto.
Adding a provided scope to the dependency solved that problem.

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.

Tuesday, July 20, 2004

Checking for null or empty string values

Flow control can be accomplished using the <c:if>
Its test attribute can contain an EL expression.
To test if a value is null you can compare the attribute to null like:
    <c:if test="${valueToTest eq null}">
If the value exists but is empty you can test it using:
    <c:if test="${empty valueToTest}">
I assumed that the empty operator was a binairy operator but after thourough testing it appeared to be a unairy operator.

Tuesday, June 01, 2004

Map iterations using c:forEach

Using the c:forEach custom tag, it is easy to iterate over collections including map's.
Altough you have to keep in mind that the resulting value is a MapItem.

The MapItem has 2 properties named key and value.
These properties can be treated as javabeans theirselves, hence its properties being retrieved according to the javabean specification.
Hereunder follows a sample that iterates over a map, the key is of type String and the value of a type that complies to the javabean specification:

<table>
<c:forEach var="item" items="myMap">
<tr>
<td>
<c:out value="${item.key}"/>
</td>
<td>
<c:out value="${item.value.givenName}"/>
</td>
<td>
<c:out value="${item.value.surName}"/>
</td>
</tr>
</c:forEach>
</table>
The output of the above sample is:

1JohnDoe
2JaneDoe
3Johnny jr.Doe

Friday, May 14, 2004

Using custom objects in JSTL's expression language

If you are going to use JSTL's expression language, take care that the attributes you want to use needs to be within scope.
Usually the necessary attributes wil be available on the request, session or pagecontext. But sometimes you need to use a variable, or constant, that is NOT available yet. In that case you have to add it to the opagecontext yourself.

This can be achieved using a scriptlet:

<%
pageContext.setAttribute("myVar", MyClass.myConstant);
%>

But you can also achieve using the jstl tag c:set:

<c:set var="myVar"><%=MyClass.myConstant%></c:set>

Now it can be used in EL expressions within jstl tags:
<c:out value="${myVar.name}"/>