Fórum

Getting Liferay Datasource in portlet not generated by Plugins SDK

thumbnail
Adam Victor Nazareth Brandizzi, modificado 12 Anos atrás.

Getting Liferay Datasource in portlet not generated by Plugins SDK

Junior Member Postagens: 67 Data de Entrada: 30/04/10 Postagens Recentes
Hello, all.

First of all, I am using Liferay 6.0 EE SP2 in Tomcat 6.0.32.

I am trying to deploy some portlets in Liferay. These portlets are legacy code made by people who did not knew a lot about how Liferay works at the time and made, let us say, "amazing" decisions, such as to map Liferay Service Builder entity tables to new classes. These portlets are seamed by Spring and mapped to database by Hibernate. To avoid the annoying requirement of editing context.xml (which is tiresome, error prone, easily forgettable, makes the persistence layer slow as hell etc.) I provided the Liferay datasource as a new bean...

    <bean id="liferayDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <bean class="com.liferay.portal.kernel.util.InfrastructureUtil" factory-method="getDataSource" />
        </property>
    </bean>


...and used this new bean as the datasource of the Entity Manager Factory:

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="liferayDataSource" />
        <property name="persistenceUnitName" value="liferay-db" />
    </bean>


If I have the Liferay running and I deploy my portlets, it runs without problem because the Liferay resources are already available. The problem is, when I restart Liferay these portlets are loaded before the Liferay app going up, so the InfrastructureUtil class is not even loaded yet. The dependencies are not satisfied and the plugin cannot be loaded. This problem, however, does not happen when deploying portlets generated by Plugins SDK, even when they contain services generated by Service Builder.

So, how could I solve this problem? I wonder about two possible solutions:

  • Could I delay the loading of my portlet, in such a way it will be loaded after Liferay?
  • Could I delay the loading of the Spring context of the portlet, or make the context loading lazy / on-demand?


Are they viable? What other solutions could I try?
thumbnail
David H Nebinger, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Liferay Legend Postagens: 14917 Data de Entrada: 02/09/06 Postagens Recentes
If you make the portlet that is failing have a required context dependency w/ the portlet that needs to go first (in liferay-plugin-package.properties file), Liferay will not load the portlet until the required one is loaded.
thumbnail
Adam Victor Nazareth Brandizzi, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Junior Member Postagens: 67 Data de Entrada: 30/04/10 Postagens Recentes
David H Nebinger:
If you make the portlet that is failing have a required context dependency w/ the portlet that needs to go first (in liferay-plugin-package.properties file), Liferay will not load the portlet until the required one is loaded.


Thank you, David!

But how do I define such dependency? I just found about the recommended-deployment-context property, which does not seem to be the way to go. There is also the deployment-settings property, but I do not know how to fill it neither if it is the necessary one.

Thanks in advance!
thumbnail
Adam Victor Nazareth Brandizzi, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Junior Member Postagens: 67 Data de Entrada: 30/04/10 Postagens Recentes
Apparently, I can define a dependency context using the required-deployment-contexts in liferay-plugin-package.properties. However, I just do not know what is the name of the Liferay context! Since it is the context root, should the name be empty? Or is named ROOT (which I doubt, because it did not work)?

Thanks in advance!
thumbnail
David H Nebinger, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Liferay Legend Postagens: 14917 Data de Entrada: 02/09/06 Postagens Recentes
Empty for the ROOT context, otherwise the portlet context to get a portlet-specific instance.
thumbnail
Adam Victor Nazareth Brandizzi, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Junior Member Postagens: 67 Data de Entrada: 30/04/10 Postagens Recentes
David H Nebinger:
Empty for the ROOT context, otherwise the portlet context to get a portlet-specific instance.


Thank you again, David

However, I have one more question: how could I set the property as the empty string in the liferay-plugin-package.properties? I have tried to do it in various ways; none worked:


required-deployment-contexts=
required-deployment-contexts=""
required-deployment-contexts=   # Some spaces after the property name
required-deployment-contexts=,     # I supposed the parser would consider the property as two empty strings separated by a comma


Is there a way to do it?

Thanks in advance again!
thumbnail
David H Nebinger, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Liferay Legend Postagens: 14917 Data de Entrada: 02/09/06 Postagens Recentes
You don't need it. The Liferay context is guaranteed to be there, otherwise the portlets wouldn't work!

You only need to add to the required deployment context if the service builder stuff is specified in another portlet.

I.e. Portlet A has the service.xml and all of the appropriate service builder classes. Portlet B, which uses the service from Portlet A, should list Portlet A as a required deployment context.

But all portlets have an implied required deployment context on root.
thumbnail
Adam Victor Nazareth Brandizzi, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Junior Member Postagens: 67 Data de Entrada: 30/04/10 Postagens Recentes
Hello again, David. Thank you for your help.

David H Nebinger:
You don't need it. The Liferay context is guaranteed to be there, otherwise the portlets wouldn't work!

You only need to add to the required deployment context if the service builder stuff is specified in another portlet.

I.e. Portlet A has the service.xml and all of the appropriate service builder classes. Portlet B, which uses the service from Portlet A, should list Portlet A as a required deployment context.

But all portlets have an implied required deployment context on root.


Unfortunately, this is not the case, at least at Liferay EE SP2. The context of my portlets are loading before the context of Liferay itself and so they not only are not working - they are preventing Tomcat of loading another contexts correctly as well. When my portlet loads, I got the log below (that is available, too, in the attached log file):

INFO: Deploying configuration descriptor [OMITTED-PORTLET-NAME]-portlet.xml
2012-03-21 12:36:02,571 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0'
defined in URL 
[file:[PATH-TO-LIFERAY]/tomcat-6.0.32/temp/2-[OMITTED-PORTLET-NAME]-portlet/WEB-INF/classes/application-context-DAO.xml]: 
Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'entityManagerFactory' defined in URL 
[file:[PATH-TO-LIFERAY]/tomcat-6.0.32/temp/2-[OMITTED-PORTLET-NAME]-portlet/WEB-INF/classes/application-context-EntityManager.xml]:
Cannot resolve reference to bean 'liferayDataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liferayDataSource' defined in URL 
[file:[PATH-TO-LIFERAY]/tomcat-6.0.32/temp/2-[OMITTED-PORTLET-NAME]-portlet/WEB-INF/classes/application-context-Liferay.xml]:
Cannot create inner bean 'com.liferay.portal.kernel.util.InfrastructureUtil#673dd208' of type [com.liferay.portal.kernel.util.InfrastructureUtil]
while setting bean property 'targetDataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'com.liferay.portal.kernel.util.InfrastructureUtil#673dd208' defined in URL
[file:[PATH-TO-LIFERAY]/tomcat-6.0.32/temp/2-[OMITTED-PORTLET-NAME]-portlet/WEB-INF/classes/application-context-Liferay.xml]:
Initialization of bean failed; nested exception is java.lang.NullPointerException


To add insult to injury, after the portlet fails to load I got this message:

21/03/2012 12:36:02 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
GRAVE: The web application [/[OMITTED-PORTLET-NAME]-portlet] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.


So the JDBC driver is unloaded and the Liferay cannot go up because it depends upon this driver. However, as you already said, this does not happen when using portlets with their own services (and that, as a consequence, also use the Liferay data source).

Do you understand my point better now?

Anyway, thanks again.
thumbnail
David H Nebinger, modificado 12 Anos atrás.

RE: Getting Liferay Datasource in portlet not generated by Plugins SDK

Liferay Legend Postagens: 14917 Data de Entrada: 02/09/06 Postagens Recentes
The key is probably going to be found in the creation of a new service builder-based portlet. Those too will use the LiferayDataSource and their context gets loaded before the root context. I'm guessing if you imitate how the SB portlet creates the LiferayDataSource (check the src/META-INF/*.xml files), you'll find the key for instantiating the data source in your own portlet.