留言板

Portlet with separate database

Henrik Bernström,修改在13 年前。

Portlet with separate database

Junior Member 帖子: 43 加入日期: 07-10-5 最近的帖子
Hi,

I'm using Milen Dyankov's maven archetype to generate a portlet for Liferay 5.2.3 and it works really nice. I succeed in developing a portlet using the service builder and it works as long as it is configured to use the standard liferay datasource, but when trying to set it up to go towards a separate database it fails in deploying with this exception:

10:44:42,585 ERROR [ContextLoader:215] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionAdvice' defined in ServletContext resource [/WEB-INF/classes/META-INF/base-spring.xml]: Cannot resolve reference to bean 'hitnetTransactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hitnetTransactionManager' is defined
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
...

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hitnetTransactionManager' is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
...


My service.xml is set up like this:


<!--?xml version="1.0"?-->


<service-builder package-path="nu.hitnet.portlet.serviceapplication">
	<namespace>Services</namespace>
	<entity name="Online" local-service="true" remote-service="true">

		<column name="dateTime" type="Date" />
		<column name="username" type="String" />
		<column name="framedIpAddress" type="String" />
		<column name="nasPortId" type="String" />
		<column name="acctSessionId" type="String" primary="true" />
		<column name="nasIdentifier" type="String" />
		<column name="nasIpAddress" type="String" />

		<!-- Order -->
		<order by="asc">
			<order-column name="nasIpAddress" />
		</order>

		<!-- Finder methods -->
		<finder name="NasIpAddress" return-type="Online" unique="true">
			<finder-column name="nasIpAddress" />
		</finder>
	</entity>
</service-builder>


I have my datasources set up in {liferay_5.2.3}/tomcat/conf/context.xml


<context>
        <resource name="jdbc/LiferayPool" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/lportal?useUnicode=true&amp;characterEncoding=UTF-8&amp;useFastDateParsing=false" username="xxx" password="xxx" maxActive="20" />
              
        <resource name="jdbc/HitnetPool" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/radius?useUnicode=true&amp;characterEncoding=UTF-8&amp;useFastDateParsing=false" username="xxx" password="xxx" maxActive="20" />
</context>


and I'm pointing them out in my portal-ext.properties that is located directly in the {liferay_5.2.3} folder:

### MYSQL ###
        jdbc.default.jndi.name=jdbc/LiferayPool
        jdbc.hitnet.jndi.name=jdbc/HitnetPool


I have configured hibernate-spring-hitnet.xml:


<!--?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">
	<bean id="hitnetHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
		<property name="dataSource" ref="hitnetDataSource" />
	</bean>
	<bean id="hitnetSessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl">
		<property name="sessionFactoryImplementor" ref="hitnetHibernateSessionFactory" />
	</bean>
	<bean id="hitnetTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
		<property name="dataSource" ref="hitnetDataSource" />
		<property name="globalRollbackOnParticipationFailure" value="false" />
		<property name="sessionFactory" ref="hitnetHibernateSessionFactory" />
	</bean>
</beans>


and infrastructure-spring-hitnet.xml:


<!--?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">
	<bean id="hitnetDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
		<property name="targetDataSource">
			<bean class="com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean">
				<property name="propertyPrefix" value="jdbc.hitnet." />
			</bean>
		</property>
	</bean>
</beans>


which are then added to my service-ext.properties:


	
##
## Spring
##

    #
    # Input a list of comma delimited Spring configurations. These will be
    # loaded after the bean definitions specified in the contextConfigLocation
    # parameter in web.xml.
    #
    spring.configs=\
        WEB-INF/classes/META-INF/base-spring.xml,\
        \
        WEB-INF/classes/META-INF/hibernate-spring.xml,\
        WEB-INF/classes/META-INF/infrastructure-spring.xml,\
        \
        WEB-INF/classes/META-INF/hibernate-spring-hitnet.xml,\
        WEB-INF/classes/META-INF/infrastructure-spring-hitnet.xml,\
        \
        WEB-INF/classes/META-INF/portlet-spring.xml,\
        \
        WEB-INF/classes/META-INF/ext-spring.xml


Finally my base-spring.xml is changed to use hitnetTransactionManager:


<!--?xml version="1.0" encoding="UTF-8"?-->

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	<bean id="beanReferenceAnnotationBeanPostProcessor" class="com.liferay.portal.spring.annotation.BeanReferenceAnnotationBeanPostProcessor" />
	<aop:config>
		<aop:pointcut id="transactionOperation" expression="bean(*Service.impl)" />
		<aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionOperation" />
	</aop:config>
	<bean id="transactionAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor">
		<property name="transactionManager" ref="hitnetTransactionManager" />
		<property name="transactionAttributeSource">
			<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
				<constructor-arg>
					<bean class="com.liferay.portal.spring.annotation.PortalTransactionAnnotationParser" />
				</constructor-arg>
			</bean>
		</property>
	</bean>
	<bean id="portletBeanFactoryPostProcessor" class="com.liferay.portal.spring.context.PortletBeanFactoryPostProcessor" />
	<bean id="portletClassLoader" class="com.liferay.portal.kernel.portlet.PortletClassLoaderUtil" factory-method="getClassLoader" />
	<bean id="logAdvice" class="com.liferay.portal.spring.aop.LogAdvice" />
	<bean id="velocityServiceInterceptor" class="com.liferay.portal.spring.aop.BeanInterceptor">
		<property name="classLoader" ref="portletClassLoader" />
		<property name="exceptionSafe" value="true" />
	</bean>
	<bean id="baseVelocityService" abstract="true">
		<property name="interceptorNames">
			<list>
				<value>velocityServiceInterceptor</value>
			</list>
		</property>
	</bean>
	<bean id="baseModelExtensionAdvice" class="com.liferay.portal.spring.aop.ModelExtensionAdvice" abstract="true" />
	<bean id="basePersistence" abstract="true">
		<property name="dataSource" ref="hitnetDataSource" />
		<property name="sessionFactory" ref="hitnetSessionFactory" />
	</bean>
</beans>


Sorry for the long post, but I didn't want to miss out with the details.

So,... I'm quite stuck. Thankful for any advice!

Regards!
/Henrik
thumbnail
Milen Dyankov,修改在13 年前。

RE: Portlet with separate database

Regular Member 帖子: 171 加入日期: 09-9-23 最近的帖子
This is shot in the dark but (in case you haven't done so) try to add


<!-- Spring XmlWebApplicationContext class -->
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>com.liferay.portal.spring.context.PortletApplicationContext</param-value>
	</context-param>

<!-- Listener that starts up the XmlWebApplicationContext IOC container (bean factory) -->
	<listener>
		<listener-class>com.liferay.portal.kernel.spring.context.PortletContextLoaderListener</listener-class>
	</listener>


to your web.xml and see if it helps.
Henrik Bernström,修改在13 年前。

RE: Portlet with separate database

Junior Member 帖子: 43 加入日期: 07-10-5 最近的帖子
Thanks for the response Milen! Though it didn't solve my problem, unfortunately.

I have come a bit further myself. I now don't get any exception when deploying or running but on the other hand, even if the database connection is there I simply get no data back from my calls. The table has been manually created by the sql created from the service builder.

What I changed in my portlet was to _not_ use hibernate-spring-hitnet.xml and infrastructure-spring-hitnet.xml but on the other hand modify the generated ones (hibernate-spring.xml and infrastructure-spring.xml).

 hibernate-spring.xml
<!--?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">
	<bean id="hitnetHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
		<property name="dataSource" ref="hitnetDataSource" />
	</bean>
	<bean id="hitnetSessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl">
		<property name="sessionFactoryImplementor" ref="hitnetHibernateSessionFactory" />
	</bean>
	<bean id="hitnetTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
		<property name="dataSource" ref="hitnetDataSource" />
		<property name="globalRollbackOnParticipationFailure" value="false" />
		<property name="sessionFactory" ref="hitnetHibernateSessionFactory" />
	</bean>
</beans>


 infrastructure-spring.xml
<!--?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">
	<bean id="hitnetDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
		<property name="targetDataSource">
			<bean class="com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean">
				<property name="propertyPrefix" value="jdbc.hitnet." />
			</bean>
		</property>
	</bean>
</beans>


No auto-create or auto-update is working.
thumbnail
Milen Dyankov,修改在13 年前。

RE: Portlet with separate database

Regular Member 帖子: 171 加入日期: 09-9-23 最近的帖子
I guess you have already read Connecting to Separate Database Using Build-service in Plugins SDK wiki page. One thing I have noticed comparing your approach to what's described there is that you didn't tell your entity to use the new database. In service.xml you have

<entity name="Online" local-service="true" remote-service="true">
</entity>

while according to the article it should probably be

<entity name="Online" local-service="true" remote-service="true" data-source="hitnetDataSource">
</entity>


If this does not help you may try to build the code aside (or create a sample project) using standard Liferay SDK (without liferay-maven-sdk) to eliminate potential bugs in liferay-maven-sdk. If the problem is still there with Liferay SDK it is more likely to get some help from Liferay staff.

If it works with LiferaySDK, please compare the output of both SDK and let me know what the differences are.
Henrik Bernström,修改在13 年前。

RE: Portlet with separate database

Junior Member 帖子: 43 加入日期: 07-10-5 最近的帖子
Thanks again, Milen.

Yes, I have studied that article. I can't remember why I actually removed those attributes (data-source, session-factory and tx-manager) but I added them again and rebuild the service. What those attributes finally will affect is only the *ModelImpl class setting the static fields like this:

OnlineModelImpl.java
...
	public static final String DATA_SOURCE = "hitnetDataSource";
	public static final String SESSION_FACTORY = "hitnetSessionFactory";
	public static final String TX_MANAGER = "hitnetTransactionManager";
...


Those are though not referenced from anywhere, by default, as I can see. So, the attributes in service.xml aren't affecting the generated spring configurations.

I also tried generating the same stuff using the standard Plugins SDK (not using maven) and the result is the same. Sorry if you thought I was pointing finger at you in my initial post, I didn't intend to. So yes, anyone from the Liferay staff (or the community) is addressed by my issues, not only you. emoticon

The one thing I'm uncertain of now is the conf/context.xml referenced in your previous link.

 /conf/context.xml
	<resource name="jdbc/TrainingPool" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/training?useUnicode=true&amp;characterEncoding=UTF-8" username="lportal" password="lportal" maxActive="20" />


Question: where is this file located? Within tomcat? Should I create it within my portlet project?

Thanks in advance!
thumbnail
Olaf Kock,修改在13 年前。

RE: Portlet with separate database

Liferay Legend 帖子: 6403 加入日期: 08-9-23 最近的帖子
Sorry, I can't currently set aside more time to check your issues, but can give a quick hint: The xml-snippet for <Resource> you mentioned is a part of tomcat's context descriptor. It declares a Datasource entry for JNDI that you might place in $TOMCAT_HOME/conf/context.xml to have it globally available or in your plugin in META-INF/context.xml within a <Context> element or in conf/Catalina/localhost/${your-plugin's-context-name}.xml (if you left your Engine and Hostname in server.xml untouched.

So conf/context.xml recommends to do it globally which would be ok for development purposes. In production you would put it closer to the plugin(s) you want to access the database instead of the global scope.
Henrik Bernström,修改在13 年前。

RE: Portlet with separate database

Junior Member 帖子: 43 加入日期: 07-10-5 最近的帖子
Thanks for your time, Olaf!

I changed my infrastructure-spring.xml to:


	<bean id="hitnetDataSourceTarget" class="com.liferay.portal.spring.jndi.JndiObjectFactoryBean" lazy-init="true">
		<property name="jndiName">
			<value>jdbc/HitnetPool</value>
		</property>
	</bean>


and now it seems to work. I have read numerous articles regarding the issue so I might have mixed details and finally got lost.

Thanks for all the help guys!

/Henrik