Using JNDI managed DataSources

uPortal 3.0.0 is templated out-of-the-box to use a direct connection to its datasource. That is, it connects directly to the datasource using the provided details such as DB address, username, password, etc. This works for both build-time and run-time operations. But what if you want to take advantage of JNDI and use a JNDI managed datasource instead of a direct connection? Well you can!

This documentation will describe how to make use of a JNDI resource. Creating and managing a JNDI resource is container specific and beyond the scope of uPortal documentation. Please refer to your container documentation.

Build-time v Run-time datsources

The big difference between built-time and run-time, so far as datasources are concerned, is that at build-time uPortal is not being run inside the J2EE Web Application Container (eg Tomcat). This means that uPortal at built-time does not have access to any resources defined and created by the container, such as JNDI resources. So, at build-time uPortal must use a direct connection to its datasource as it can't use a JNDI resource.

At run-time, however, uPortal is being run inside the J2EE Web Application Container and thus has access to its resources. In this case, uPortal can make use of a JNDI resource to connect to its datasource and take advantage of the benefits gained from using a JNDI managed datasource.

With that now clear, it is easy to see that if we configure uPortal to solely use a JNDI resource for its datasource connection, all datasource operations performed at build-time will fail, but all operations at run-time will succeed plus it gets the advantages of JNDI. But, if we configure uPortal to use solely a direct connection to its datasource, all datasource operations (both at build and run time) will succeed, but without the advantages of using JNDI.

So, if we want to use JNDI, we need the best of both worlds! We need to use direct connection for all built-time operations, while using JNDI for all run-time operations.

Configuring uPortal to use a JNDI resource for run-time operations

Datasources in uPortal 3 are defined using Spring beans and are configured in the datasource context configuration file:

uportal-impl/src/main/resources/properties/contexts/datasourceContext.xml

It is predefined, as follows, to create a direct connection to the datasource using the connection properties found in the rdbm.properties file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!--
     | DataSource objects used by the portal should be configured
     +-->
    <bean id="PortalDb" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${hibernate.connection.driver_class}" />
        <property name="url" value="${hibernate.connection.url}" />
        <property name="username" value="${hibernate.connection.username}" />
        <property name="password" value="${hibernate.connection.password}" />

        <property name="maxActive" value="50" />
        <property name="maxIdle" value="10" />
        <property name="maxWait" value="1000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="300" />
        <property name="logAbandoned" value="true" />
    </bean>

    <bean id="PortalDB.metadata" class="org.jasig.portal.rdbm.DatabaseMetaDataImpl">
        <constructor-arg index="0" ref="PortalDb" />
    </bean>

    <alias alias="PersonDB" name="PortalDb"/>

    <bean id="rdbmPropertiesPlacholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="false">
        <property name="location" value="classpath:/properties/rdbm.properties" />
    </bean>
</beans>

'PortalDb' is hard coded in the uPortal code as the ID of the Spring bean which provides the datasource to uPortal. The 'PortalDb' bean above is a direct connection datsource. A JNDI managed datasource would be defined as follows (with the 'jndiName' property value being set to the name of your JNDI resource):

<bean id="PortalDb" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/uPortalDB" />
</bean>

To get the best of both worlds, we need the 'PortalDb' bean to not be a direct datasource nor a JNDI datasource but instead, be a custom bean which mediates between JNDI and direct connection and returns the appropriate datasource ready for use. Using the attached custom class (org.jasig.portal.spring.beans.factory.MediatingFactoryBean) we can configure the 'PortalDb' bean to automatically be either a JNDI managed datasource if it is available (ie at run-time) or a direct connection datasource if JNDI is not available (ie at build-time). The datsourceContext.xml file would now look like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!--
     | DataSource objects used by the portal should be configured
     +-->
    <bean id="PortalDb" class="org.jasig.portal.spring.beans.factory.MediatingFactoryBean">
	<property name="type" value="javax.sql.DataSource" />
	<property name="delegateBeanNames">
		<list>
			<value>PortalDb.JNDI</value>
			<value>PortalDb.direct</value>
		</list>
	</property>
    </bean>

    <bean id="PortalDb.JNDI" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/uPortalDB" />
    </bean>

    <bean id="PortalDb.direct" class="org.apache.commons.dbcp.BasicDataSource" lazy-init="true">
        <property name="driverClassName" value="${hibernate.connection.driver_class}" />
        <property name="url" value="${hibernate.connection.url}" />
        <property name="username" value="${hibernate.connection.username}" />
        <property name="password" value="${hibernate.connection.password}" />

        <property name="maxActive" value="50" />
        <property name="maxIdle" value="10" />
        <property name="maxWait" value="1000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="300" />
        <property name="logAbandoned" value="true" />
    </bean>

    <bean id="PortalDB.metadata" class="org.jasig.portal.rdbm.DatabaseMetaDataImpl">
        <constructor-arg index="0" ref="PortalDb" />
    </bean>

    <alias alias="PersonDB" name="PortalDb"/>

    <bean id="rdbmPropertiesPlacholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="false">
        <property name="location" value="classpath:/properties/rdbm.properties" />
    </bean>
</beans>
 
Using this configuration allows us to have the best of both worlds.

Having problems with these instructions?

Please send us feedback at uportal-user@lists.ja-sig.org