Reputation: 14949
I have a servicebuilder portlet that is configured via JNDI:
<Context antiJARLocking="true" useHttpOnly="true">
<ResourceLink name="app/url" global="my-app/app/url"
type="java.lang.String" />
</Context>
In my ext-spring.xml
, I try to pull that value using:
<jee:jndi-lookup jndi-name="java:comp/env/app/url" />
However, the InitialContext
that is used to look this value up, seems to be the InitialContext
of the ROOT
webapp (liferay itself) as the only thing it contains is the java:comp/env/jdbc/LiferayPool
database connection pool. I know JNDI contexts are tied to the the ClassLoader
determined by:
Thread.currentThread().getContextClassLoader();
And I know liferay mucks with the classloader before running the portlet initialization. But I cannot, for the life of me, figure out how to get around this. Any suggestions?
Upvotes: 0
Views: 1283
Reputation: 475
I have a working solution for you but it is a little bit different of what you've described in your post.
First of all, I propose you to move the declaration of JNDI to server.xml of Tomcat, specifically to < GlobalNamingResources > tag.
Here is an example:
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource
name="jdbc/CustomDBPoolShared"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@YOUR_SERVER:1521:YOUR_SERVICE"
username="USERNAME"
password="PASSWORD"
maxActive="20"
maxIdle="5"
maxWait="10000"
/>
......
</GlobalNamingResources>
After that you should make a ResourceLink in context.xml:
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<ResourceLink name="jdbc/CustomDBPool" global="jdbc/CustomDBPoolShared" type="javax.sql.DataSource"/>
....
</Context>
This will help you to deal with concurrent access if ever you'll have two portlets accessing the same database.
And, finally, ext-spring.xml:
<!-- Custom Beans -->
<bean id="digitalHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration" lazy-init="true">
<property name="dataSource">
<ref bean="customDBDataSource"/>
</property>
</bean>
<bean id="customDBSessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl" lazy-init="true">
<property name="sessionFactoryImplementor">
<ref bean="digitalHibernateSessionFactory" />
</property>
</bean>
<bean id="customDBDataSourceTarget" class="com.liferay.portal.spring.jndi.JndiObjectFactoryBean" lazy-init="true">
<property name="jndiName">
<value>jdbc/customDBPool</value>
</property>
</bean>
<bean id="customDBDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy" lazy-init="true">
<property name="targetDataSource">
<ref bean="customDBDataSourceTarget" />
</property>
</bean>
Notice the jdbc/customDBPool
Please note the jdbc/customDBPool which is described in context.xml and which is available not only for ROOT classloader.
In the end you should reference the proper dataSource in your service.xml of LiferayServiceBuilder like that:
<entity name="MyCustomEntity" table="CUSTOM_ENTITY" local-service="true" remote-service="false" data-source="customDBDataSource" session-factory="customDBSessionFactory" cache-enabled="false">
.....
</entity>
Upvotes: 1