Showing 29 Comments
Jonas Yuan
2/19/09 3:07 AM
Sweet! Thank you, Ray!
Jonas Yuan
2/19/09 8:47 AM
Hi Ray,
The following code (spring beans) exists in util-spring.xml. Do we need to specify them again in /src/META-INF/ext-spring.xml?
Thanks
Jonas Yuan
----
<bean id="velocityUtilInterceptor" class="com.liferay.portal.spring.aop.BeanInterceptor">
<property name="exceptionSafe" value="true" />
</bean>
<bean id="baseVelocityUtil" abstract="true">
<property name="interceptorNames">
<list>
<value>velocityUtilInterceptor</value>
</list>
</property>
</bean>
Peter Mesotten
3/26/09 7:17 AM
When trying to get a reference to my custom util class, my VM parser shows this error:
Invocation of method 'findUtil' in class com.liferay.portal.velocity.UtilLocator threw exception com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set at com.liferay.portlet.journal.util.JournalVmUtil[line 22, column 14]
Any idea what this means?
Hmm, strange. Can you describe when and where your template is being called?
Peter Mesotten
3/26/09 8:21 AM
I'm working with 5.2.1.
I created a simple web content article. In my template I call:
$utilLocator.findUtil("custom-utils", "be.aca.tools.util.UserToolUtil")
When I navigate to the article on my page, the previously mentioned error shows together with the velocity code itself. In the catalina.out i get: BeanLocator is null.
I created a project (custom-utils) in the plugins SDK with IUserTool, UserToolImpl and UserToolUtil. My ext-spring.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="velocityUtilInterceptor" class="com.liferay.portal.spring.aop.BeanInterceptor">
<property name="exceptionSafe" value="true"/>
</bean>
<bean id="baseVelocityUtil" abstract="true">
<property name="interceptorNames">
<list>
<value>velocityUtilInterceptor</value>
</list>
</property>
</bean>
<bean id="be.aca.tools.ifc.IUserTool" class="be.aca.tools.impl.UserToolImpl"/>
<bean id="be.aca.tools.util.UserToolUtil" class="be.aca.tools.util.UserToolUtil">
<property name="userTool" ref="be.aca.tools.ifc.IUserTool"/>
</bean>
<bean id="be.aca.tools.util.UserToolUtil.velocity" class="org.springframework.aop.framework.ProxyFactoryBean" parent="baseVelocityUtil">
<property name="target" ref="be.aca.tools.ifc.IUserTool"/>
</bean>
</beans>
AHH!... My fault. I should have stated that the ability to inject from a plugin also requires ServiceBuilder.
So, the simplest solution is to create a service.xml file in your plugin with a single entity having no columns defined, like:
<service-builder package-path="be.aca">
<namespace>ACA</namespace>
<entity name="ACA" local-service="true" remote-service="false" />
</service-builder>
then do ant build-service.
Now your ext-spring file should be read, it isn't being read currently.
Peter Mesotten
3/26/09 8:53 AM
Thanks alot for your fast answer Ray.
During the build-service task I'm getting the following error stack:
[java] org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [be.aca.tools.UserToolImpl] for bean with name 'be.aca.tools.IUserTool' defined in class path resource [META-INF/ext-spring.xml]; nested exception is java.lang.ClassNotFoundException: be.aca.tools.UserToolImpl
[java] at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1138)
[java] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:522)
[java] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1174)
[java] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:754)
[java] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:422)
[java] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
[java] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
[java] at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
[java] at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
[java] at com.liferay.portal.spring.context.ArrayApplicationContext.<init>(ArrayApplicationContext.java:40)
[java] at com.liferay.portal.spring.util.SpringUtil.getContext(SpringUtil.java:52)
[java] at com.liferay.portal.bean.BeanLocatorImpl.locate(BeanLocatorImpl.java:59)
[java] at com.liferay.portal.kernel.bean.PortalBeanLocatorUtil.locate(PortalBeanLocatorUtil.java:58)
[java] at com.liferay.portal.kernel.util.FileUtil._getUtil(FileUtil.java:295)
[java] at com.liferay.portal.kernel.util.FileUtil.getFile(FileUtil.java:132)
[java] at com.liferay.portal.kernel.util.FileUtil.exists(FileUtil.java:98)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.java:581)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.java:392)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.main(ServiceBuilder.java:162)
[java] Caused by: java.lang.ClassNotFoundException: be.aca.tools.UserToolImpl
[java] at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
[java] at java.security.AccessController.doPrivileged(Native Method)
[java] at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
[java] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
[java] at org.springframework.util.ClassUtils.forName(ClassUtils.java:249)
[java] at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:381)
[java] at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1135)
[java] ... 18 more
Note: I've put all my classes in the "be.aca.tools" package of my plugin
> Note: I've put all my classes in the "be.aca.tools" package of my plugin
And those are in WEB-INF/src/ ? or in a jar in WEB-INF/lib/ ?
Peter Mesotten
3/27/09 12:39 AM
They're inside WEB-INF/src indeed.
Peter Mesotten
3/27/09 12:49 AM
It works! I'm just stupid... I of course had to ant compile my source files first before running build-service, because my source files were moved. Now, the beans are correctly created and the service is built.
Thanks alot!
Peter Mesotten
3/27/09 1:32 AM
Hm I was too fast. On the GUI, the same error still arises. I debugged in PortletBeanLocatorUtil and saw that the _beanLocators map only has a value for the wol-portlet...
Also, I had pointed my ant scripts to the wrong tomcat server. Now, when I build-service, the script output shows:
Buildfile: C:\Workspaces\liferay\Liferay\hooks\custom-utils\build.xml
build-service:
[java] Loading jar:file:/C:/Projects/Liferay/Liferay%205.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/system.properties
[java] Loading file:/C:/Projects/Liferay/Liferay%205.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/classes/system-ext.properties
[java] Loading jar:file:/C:/Projects/Liferay/Liferay%205.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/portal.properties
[java] Loading file:/C:/Projects/Liferay/Liferay%205.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/classes/portal-ext.properties
[java] 08:32:18,867 INFO [DialectDetector:65] Determining dialect for MySQL 5
[java] 08:32:18,977 INFO [DialectDetector:98] Using dialect org.hibernate.dialect.MySQLDialect
[java] Loading jar:file:/C:/Projects/Liferay/Liferay%205.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/captcha.properties
[java] 08:32:23,852 INFO [PortalImpl:237] Portal lib directory /C:/Projects/Liferay/Liferay 5.2/tomcat-5.5.27/webapps/ROOT/WEB-INF/lib/
[java] 08:32:32,947 INFO [ServerDetector:76] Detected server null
[java] Building ACA
[java] Writing docroot\WEB-INF\src\be\aca\tools\service\base\ACALocalServiceBaseImpl.java
[java] Writing docroot\WEB-INF\src\be\aca\tools\service\impl\ACALocalServiceImpl.java
[java] Writing docroot\WEB-INF\src\be\aca\tools\service\ACALocalService.java
[java] Writing docroot\WEB-INF\src\be\aca\tools\service\ACALocalServiceFactory.java
[java] Writing docroot\WEB-INF\src\be\aca\tools\service\ACALocalServiceUtil.java
After this last line, the script seems to pause so I have to manually stop it.. So I suppose the service is not correctly built...
I've seen this before. Do you have clustering enabled? If so, disable it when trying to build.
Peter Mesotten
3/30/09 7:14 AM
Nope, no clustering. Just working locally with one instance..
I just tried the same on my Liferay 5.1.1 instance (the version we're using on our production server). The build-service task now outputs the following:
Buildfile: C:\Workspaces\liferay\Liferay\hooks\custom-utils\build.xml
build-service:
[java] Loading jar:file:/C:/Projects/Liferay/Liferay511/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/system.properties
[java] Manually loading Spring context
[java] Loading jar:file:/C:/Projects/Liferay/Liferay511/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/portal.properties
[java] Loading file:/C:/Projects/Liferay/Liferay511/webapps/ROOT/WEB-INF/classes/portal-ext.properties
[java] Building ACA
[java] java.lang.StringIndexOutOfBoundsException: String index out of range: -1
[java] at java.lang.String.substring(String.java:1938)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder._createHBMXML(ServiceBuilder.java:1622)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.java:947)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.java:392)
[java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.main(ServiceBuilder.java:162)
BUILD SUCCESSFUL
Total time: 4 seconds
Any idea what's going on here?
That's really strange! Because I just tested in 5.1.x with:
<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 5.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_5_1_0.dtd">
<service-builder package-path="be.aca">
<namespace>ACA</namespace>
<entity name="ACA" local-service="true" remote-service="false" />
</service-builder>
and got no "[java] java.lang.StringIndexOutOfBoundsException: String index out of range: -1"
I didn't test on 5.2.x as I don't have a build of that.. testing trunk....
Just tested in trunk. Just added this:
<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 5.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_5_2_0.dtd">
<service-builder package-path="be.aca">
<namespace>ACA</namespace>
<entity name="ACA" local-service="true" remote-service="false" />
</service-builder>
to a portlet without any service and ran "ant build-service" and no issues.
PS: I just made a small change which (when it gets backported to 5.1.x) will allow you to skip the ServiceBuilder part and just use the spring portion.
Will Blog on that later.
Peter Mesotten
3/30/09 8:03 AM
Wow that's strange.. You chose "be.aca" as service path, while I picked "be.aca.tools", the class where all util/class/ifc files are situated. And with your path, it worked!
However, 5.1 does not have $utilLocator so I can't test if it works on the UI side. Or is there any other way to access custom util classes in 5.1?
In 5.2, the exact same problem still exists after editing the service path.
5.1. does indeed have $utilLocator.
Peter Mesotten
3/31/09 3:55 AM
You mean it doesn't exist? Because I can't find it anywhere in the 5.1 source and it is not defined in VelocityVariables.java
Peter Mesotten
3/31/09 4:35 AM
I just tried building & deploying using the 5.2 Plugins SDK (I used the 5.1 SDK until now). Both building the service and deploying on the server go fine with no errors. But on the UI, I'm still getting the same error:
Invocation of method 'findUtil' in class com.liferay.portal.velocity.UtilLocator threw exception com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set at com.liferay.portlet.journal.util.JournalVmUtil[line 22, column 14]
And in my catalina.out:
11:31:01,958 ERROR [PortletBeanLocatorUtil:52] BeanLocator is null
http://svn.liferay.com/browse/portal/branches/5.1.x/portal-impl/src/com/liferay/portal/util/UtilLocator.java
You have to use the matching SDK for the portal version. Once you get that sorted out, make sure that you have the correct context path name to access the tool in your plugin:
#set ($myTool = $utilLocator.findUtil('my-tool-portlet', 'com.mytool.MyToolUtil'))
where "my-tool-portlet" is the name of the webapp folder of the plugin.
And this most definitely works in 5.1, as I'm currently on a 5.1 based project and we're using several custom velocity tools.
Peter Fox
3/14/10 7:39 AM
Hello Ray,
Any ideas on how to integrate this approach with the new awesome Liferay 6 RC?
I'm trying migrate code from 5.2.x to liferay6 and I defined custom velocity tool from a ext-plugin.
I've checked and spring beans are being created/loaded
Currently class: com.liferay.portal.spring.aop.BeanInterceptor does not exist on liferay6 but tried to plug it into my custom-ext plugin.
I've checked and can see that utilLocator.find("customService") is working and I can see the proxy
...problem is that MethodInterceptor for some reason is not being invoked..
#set ($myTool = $utilLocator.findUtil('com.mytool.MyToolUtil')) -->ok
$myTool.operationOne() --> does nothing! nok
This aproach is not supported on liferay6 ?... should I use ServiceHookAdvice instead?
Thanks in advance..appreciate your help.
regards,
Peter
Thiago Leão Moreira
9/30/10 1:32 PM
Hey Ray,
I'm facing the same issue as described by Peter. Do you know which class can I use for replace BeanInterceptor?
Hey guys, sorry for the long silence. I finally got around to trying to figure out what the problem was.
So, you can still do this, but there is one change in 6.0. Your util class is wrapped in a proxy object to capture exceptions. The result of this wrapping is that your outer class must implement an interface. I will write a new blog to explain.
Ian White
10/19/11 3:12 PM
Ray,
Your velocity hook was working until very recently when I finally decided to do an svn update from portal trunk.
Now, the bean defined in the applicationContext.xml is not being found.
Are you able to confirm if the velocity hook functionality has been removed ?
Thanks
Ian
David García González
3/1/12 4:46 AM
Hi, I wanted to use the static methods of the class
FriendlyURLNormalizer.
public static String normalize(String friendlyURL);
## >= 6.1
#set ($fun = $portal.getClass().forName("com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil"))
## <= 6.0
#set ($fun = $portal.getClass().forName("com.liferay.portal.util.FriendlyURLNormalizer"))
$fun.normalize(...)
PS: I like the acronym!