Implementing a reusable Liferay Service Without Ext or Service Builder
April 19th, 2010 by Bert WillemsTags:Java, Liferay, Spring
In Liferay you can split your application logic vertically exposing each component as a separate independent service. This service can be consumed by your portlet applications and any other applications. Liferay itself exposes several services to you: GroupService (for managing communities) and UserService (for managing users) for example. In this article I will show you how you can create a reusable service yourself and host it in Liferay.
In this article we will build a simple hello world service, nothing to fancy (I want to leave something for you to do yourself
). We will code the service from scratch without using tools like service builder.
The project will contain 3 modules:
- A library containing the service contract
- A web application implementing the service contract
- A web application consuming the service
I hope you like this article, please let me know if you have any questions or comments. Lets get started. I assume you have read my previous article about using Maven to build Liferay applications. If not please read it first.
0. Project Setup
Please download and unzip the empty project and load it into an IDE of choice or use the command shell if you want. The project contains empty files. Please familiarizes yourself with the project structure and notice the dependencies in the different pom.xml files. Nothing special going on though.
1. Service Contract
This library contains the code contract of our HelloWorld service and a utility class which will provide easy access for non Spring portlets. Lets first set up our service contract, copy he following code into HelloWorldService.java:
package nl.devatwork.hello.world.service;
public interface HelloWorldService {
String sayHello(String name);
}
That wasn’t so bad now was it? I think you have written more complex service contracts
.
Lets implement the access utility class. Copy the following code into HelloWorldServiceUtil.java:
package nl.devatwork.hello.world.service;
public class HelloWorldServiceUtil {
private static HelloWorldService _service;
public static HelloWorldService getService() {
if (_service == null) {
throw new RuntimeException("HelloWorldService is not set");
}
return _service;
}
public void setService(HelloWorldService service) {
_service = service;
}
public static String sayHello(String name) {
return getService().sayHello(name);
}
}
Again a really simple class. It has a getter and a setter which will be used to inject our service instance into this utility class. The static sayHello method is a proxies the service method.
You can build the service contract library by executing the following command in the /hello-world-service/ folder:
mvn clean package
Copy the resulting JAR file (/hello-world-service/target/hello-world-service-1.0.0-SNAPSHOT.jar) to the /lib/ext folder of your application server. You have to do this in order to avoid class loader issues. We will use this library later.
2. Service Implementation
Now we will implement the service in a self contained web application. This application can be deployed using the auto deploy mechanism of your application server.
Lets implement the base class for our service implementation which implements the required plumbing. Copy the following code into HelloWorldServiceBaseImpl.java:
package nl.devatwork.hello.world.service.base;
import com.liferay.portal.SystemException;
import com.liferay.portal.kernel.annotation.BeanReference;
import com.liferay.portal.service.base.PrincipalBean;
import com.liferay.portal.util.PortalUtil;
import nl.devatwork.hello.world.service.HelloWorldService;
public abstract class HelloWorldServiceBaseImpl extends PrincipalBean implements HelloWorldService {
@BeanReference(name = "nl.devatwork.hello.world.service.HelloWorldService.impl")
protected HelloWorldService helloWorldService;
public HelloWorldService getHelloWorldService() {
return helloWorldService;
}
public void setHelloWorldService(HelloWorldService helloWorldService) {
this.helloWorldService = helloWorldService;
}
protected void runSQL(String sql) throws SystemException {
try {
PortalUtil.runSQL(sql);
} catch (Exception e) {
throw new SystemException(e);
}
}
}
Now that we have the plumbing in place lets concentrate on our state of the art business logic. Copy the following code into HelloWorldServiceImpl.java:
package nl.devatwork.hello.world.service.impl;
import nl.devatwork.hello.world.service.base.HelloWorldServiceBaseImpl;
public class HelloWorldServiceImpl extends HelloWorldServiceBaseImpl {
public String sayHello(String name) {
return "Hello, " + name;
}
}
Very exiting business logic isn’t it?
.
Ok, now that we have our code in place lets apply some glue to make it all work. Copy the following content to service.properties:
##
## Properties Override
##
#
# Specify where to get the overridden properties. Updates should not be made
# on this file but on the overridden version of this file.
#
include-and-override=service-ext.properties
##
## Build
##
build.namespace=DevAtWork
build.number=1
build.date=1269952033689
build.auto.upgrade=true
##
## Spring
##
#
# Input a list of comma delimited Spring configurations. These will be
# loaded after the bean definitions specified in the
# portalContextConfigLocation parameter in web.xml.
#
spring.configs=\
WEB-INF/classes/META-INF/portlet-spring.xml
Notice the last two lines. This tells Liferay to load our Spring configuration.
Lets create our Spring configuration now. Copy the following code to portlet-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" default-init-method="afterPropertiesSet" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="nl.devatwork.hello.world.service.HelloWorldService.impl" class="nl.devatwork.hello.world.service.impl.HelloWorldServiceImpl"/>
<bean id="nl.devatwork.hello.world.service.HelloWorldServiceUtil" class="nl.devatwork.hello.world.service.HelloWorldServiceUtil">
<property name="service" ref="nl.devatwork.hello.world.service.HelloWorldService.impl"/>
</bean>
</beans>
We register two beans into the Spring container. One for our service implementation instance and one for our service util.
Lets add the following code to web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<listener>
<listener-class>com.liferay.portal.kernel.spring.context.PortletContextLoaderListener</listener-class>
</listener>
</web-app>
This will load the Spring configuration for us.
Add the following code to liferay-plugin-package.properties:
name=Hello World Service Implementation module-group-id=nl.devatwork.service.impl module-incremental-version=1 short-description= change-log= page-url=http://www.devatwork.nl author=Dev @ Work licenses=Free portal-dependency-jars=hello-world-service-1.0.0-SNAPSHOT.jar
Notice that we declare a dependency on the library we deployed earlier. Liferay will load the library on our class path.
We are ready with the service implementation now. You can build the service implementation by executing the following command in the /hello-world-service-impl/ folder:
mvn clean package
Copy the resulting WAR file (/hello-world-service-impl/target/hello-world-service-impl-1.0.0-SNAPSHOT.war to the auto deploy folder of your application server. The service implementation will be installed now.
3. Consumer Implementation
Now that we have the service contract and implementation in place lets create a portlet which consumes the service.
Copy the following code into SayHelloPortlet.java:
package nl.devatwork.hello.world.portlets;
import nl.devatwork.hello.world.service.HelloWorldServiceUtil;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
public class SayHelloPortlet extends GenericPortlet {
public void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException {
String msg = HelloWorldServiceUtil.sayHello("Liferay Dev");
response.setContentType("text/html");
response.getWriter().print(msg);
}
}
Copy the following code to portlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
<portlet>
<portlet-name>SayHelloPortlet</portlet-name>
<display-name>Say Hello Portlet</display-name>
<portlet-class>nl.devatwork.hello.world.portlets.SayHelloPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Say Hello Portlet</title>
<short-title>Say Hello Portlet</short-title>
<keywords>DevAtWork</keywords>
</portlet-info>
</portlet>
</portlet-app>
Copy the following code to liferay-plugin-package.properties:
name=Hello World Portlets module-group-id=nl.devatwork.portlets module-incremental-version=1 short-description= change-log= page-url=http://www.devatwork.nl author=Dev @ Work licenses=Free portal-dependency-jars=hello-world-service-1.0.0-SNAPSHOT.jar
Copy the following code to web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> </web-app>
We are ready with the consumer implementation now. You can build the portlet by executing the following command in the /hello-world-portlets/ folder:
mvn clean package
Copy the resulting WAR file (/hello-world-portlets/target/hello-world-portlets-1.0.0-SNAPSHOT.war to the auto deploy folder of your application server. The portlet will be installed now. Add the new portlet to a page and if everything works well then it should display the message: ‘Hello, Liferay Dev’.
You can download the complete project here.
That is it for this article, I hope you enjoyed reading it and that you learned something. If you have any questions or comments please post a comment and I will get back to you as soon as I can. In the next article I will show you how you can expose the HelloWorld service as a web service so it can be consumed by external applications.

32 Replies to “Implementing a reusable Liferay Service Without Ext or Service Builder”
May 3rd, 2010 at 07:42
[...] you how you can develop custom Liferay services. In the previous article I showed you how you can implement a custom Liferay service and expose it as a web service. In this article I will show you how you can secure your service [...]
May 3rd, 2010 at 09:10
Dear
Each time I want to try to run my helloWorld method, I get a RuntimeException that the HelloWorldService is not set.
I’ve carfully followed your instructions again and again and I can’t find why. Do you have any idea what I could be doing wrong?
grtz
Stece
May 3rd, 2010 at 18:42
Helo Stece,
That message is telling you that the service implementation isn’t deployed properly. I know Liferay is very sensitive about little details. However I need to have more details in order to figure out why not.
Can you please try to compile and deploy the finished solution to see if that is working? You can download it from the post above.
If that doesn’t solve your problem, please give me the following info:
- Which Liferay version you are using
- Which application server you are using (including version number)
- Stacktrace when deploying service implementation
If anyone else has this problem, please report info request above.
Best regards,
Bert
May 4th, 2010 at 13:33
Hello Bert
When I imported your project, it all worked fine. Then I started to rename all the HelloWorld to a new name for my usage and then I started getting the service is not set exception. I probably forgot to rename a file or change a file but I can’t seem to find where.
version: 5,2,3
glassfish v3
stack:
14:31:42,116 ERROR [JSONServiceAction:160] java.lang.reflect.InvocationTargetException
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.liferay.portal.action.JSONServiceAction.getJSON(JSONServiceAction.java:148)
at com.liferay.portal.struts.JSONAction.execute(JSONAction.java:60)
at com.liferay.portal.servlet.JSONServlet.service(JSONServlet.java:77)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at com.liferay.portal.kernel.servlet.PortalClassLoaderServlet.service(PortalClassLoaderServlet.java:108)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:431)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:337)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:218)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:154)
at com.liferay.portal.servlet.filters.secure.SecureFilter.processFilter(SecureFilter.java:282)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:91)
at com.liferay.portal.kernel.servlet.PortalClassLoaderFilter.doFilter(PortalClassLoaderFilter.java:78)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:250)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:218)
at org.apache.catalina.core.StandardWrapperValve.preInvoke(StandardWrapperValve.java:460)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:139)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:186)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:719)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:657)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:96)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:187)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:719)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:657)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:651)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1030)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:142)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:719)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:657)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:651)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1030)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:242)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:180)
at com.sun.grizzly.http.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:633)
at com.sun.grizzly.http.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:570)
at com.sun.grizzly.http.DefaultProcessorTask.process(DefaultProcessorTask.java:827)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:152)
at com.sun.enterprise.v3.services.impl.GlassfishProtocolChain.executeProtocolFilter(GlassfishProtocolChain.java:71)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:103)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:89)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:67)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:56)
at com.sun.grizzly.util.WorkerThreadImpl.processTask(WorkerThreadImpl.java:325)
at com.sun.grizzly.util.WorkerThreadImpl.run(WorkerThreadImpl.java:184)
Caused by: java.lang.RuntimeException: BuurtService is not set
at be.diget.buurt.publiek.service.BuurtServiceUtil.getService(BuurtServiceUtil.java:8)
at be.diget.buurt.publiek.service.BuurtServiceUtil.sayHello(BuurtServiceUtil.java:19)
… 51 more
June 11th, 2010 at 06:30
Hi,
Thanks for your help! I’m using Liferay 5.2.3. In order to get this thing to work, I had to add the following empty sql-files inside WEB-INF/sql:
- indexes.sql
- sequences.sql
- tables.sql
I got one problem left, though. My service keeps reloading itself whenever Catalina’s standard context reload happens? I’m using Tomcat 5.5.27.
11-Jun-2010 05:14:41 org.apache.catalina.core.StandardContext reload
INFO: Reloading this Context has started
05:14:46,865 INFO [PortletHotDeployListener:381] Unregistering portlets for extextensionsweb
05:14:46,894 INFO [PortletHotDeployListener:412] 1 portlet for extextensionsweb was unregistered
Loading file:/C:/Programs/liferay523tc55/tomcat-5.5.27/temp/3-extextensionsweb/WEB-INF/classes/service.properties
05:14:47,486 INFO [PortletHotDeployListener:227] Registering portlets for extextensionsweb
05:14:47,706 INFO [PortletHotDeployListener:346] 1 portlet for extextensionsweb is available for use
August 31st, 2010 at 04:57
Hi,
[WARNING] Unable to get resource ‘org.apache.maven.plugins:maven-resources-plugi
n:pom:2.3′ from repository central (http://repo1.maven.org/maven2): Error transf
erring file: repo1.maven.org
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-resour
ces-plugin/2.3/maven-resources-plugin-2.3.pom
[WARNING] Unable to get resource ‘org.apache.maven.plugins:maven-resources-plugi
n:pom:2.3′ from repository central (http://repo1.maven.org/maven2): Error transf
erring file: repo1.maven.org
[INFO] ————————————————————————
[ERROR] BUILD ERROR
[INFO] ————————————————————————
[INFO] Error building POM (may not be this project’s POM).
Project ID: org.apache.maven.plugins:maven-resources-plugin
Reason: POM ‘org.apache.maven.plugins:maven-resources-plugin’ not found in repos
itory: Unable to download the artifact from any repository
org.apache.maven.plugins:maven-resources-plugin:pom:2.3
August 31st, 2010 at 04:58
Hi,
I am getting below error; i do not have admin rights, is that is problem? Or is there any other issue, please help on this.
[WARNING] Unable to get resource ‘org.apache.maven.plugins:maven-resources-plugi
n:pom:2.3′ from repository central (http://repo1.maven.org/maven2): Error transf
erring file: repo1.maven.org
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-resour
ces-plugin/2.3/maven-resources-plugin-2.3.pom
[WARNING] Unable to get resource ‘org.apache.maven.plugins:maven-resources-plugi
n:pom:2.3′ from repository central (http://repo1.maven.org/maven2): Error transf
erring file: repo1.maven.org
[INFO] ————————————————————————
[ERROR] BUILD ERROR
[INFO] ————————————————————————
[INFO] Error building POM (may not be this project’s POM).
Project ID: org.apache.maven.plugins:maven-resources-plugin
Reason: POM ‘org.apache.maven.plugins:maven-resources-plugin’ not found in repos
itory: Unable to download the artifact from any repository
org.apache.maven.plugins:maven-resources-plugin:pom:2.3
August 31st, 2010 at 20:32
Hello Madan,
I think this error relates to Maven. Please check the Maven website for support.
Regards,
Bert
September 1st, 2010 at 02:54
Hi Bert,
I am able to resolve this by adding proxy details, thanks.
ALso i have another questions can I build all these service, impl and portlet like this using Eclipse also, i do not want to use Maven. Will this given code can be used for that?
September 2nd, 2010 at 12:24
Hi Bret.
I updated the impl to call web service to get data. But at run time it is giving class not found even if all the jars are in the lib directory. Is there any other way to fix this.
September 2nd, 2010 at 17:01
Could not initialize class org.apache.axis.client.AxisClient
Actually it is giving this error but all necessary Jars are in web-inf\lib folder. After that I moved all jars to lib/ext then this error not coming but while calling web service it is giving error that null data is sent to service. When i use this server from any other portlet it works fine. Is there some thing special while using this in the implementation as we use “PortletContextLoaderListener”
September 14th, 2010 at 09:34
I am getting the following error.
Error creating bean with name ‘nl.devatwork.hello.world.service.HelloWorldServiceUtil’ defined in ServletContext resource [/WEB-INF/portlet-spring.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property ‘service’ of bean class [nl.devatwork.hello.world.service.HelloWorldServiceUtil]: Bean property ‘service’ is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
These are the steps I followed.
1. Created a jar test-service.jar with the following classes:
— nl.devatwork.hello.world.service.HelloWorldService
— nl.devatwork.hello.world.service.HelloWorldServiceUtil
2. Placed the test-service.jar in tomcat/shared/lib and configured tomcat to look for this classpath.
3. Created a portlet named ‘test-portlet’.
— classes/META-INF/portlet-spring.xml
— classes/service-ext.properties
portlet-spring.xml contains:
service-ext.properties contains
spring.configs=/WEB-INF/classes/META-INF/portlet-spring.xml
4. Had the following classes in In WEB-INF/src
– nl.devatwork.hello.world.service.base.HelloWorldServiceBaseImpl
– nl.devatwork.hello.world.service.impl.HelloWorldServiceImpl
5. Started tomcat and deployed portlet. Getting the error mentioned at the top.
Where am I going wrong? Please help.
September 28th, 2010 at 18:04
Hello All,
I am totally new to Spring.
Should it be
@BeanReference(name = “nl.devatwork.hello.world.service.impl.HelloWorldService”)
instead?
not the
@BeanReference(name = “nl.devatwork.hello.world.service.HelloWorldService.impl”)
February 10th, 2011 at 15:11
Hi,
I successfully deploy service and service implementation on jboss-4.2.3 and liferay 5.2.5 (EE).
I tried consuming this service in Liferay templates but always get:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘hr.vipnet.web.pricingservice.PricingService’ is defined
or
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘hr.vipnet.web.pricingservice.PricingServiceUtil’ is defined
what am i doing wrong?
Thanks.
Br,
Alan
February 10th, 2011 at 15:43
Hello Alan,
How are you consuming the service? Using the ServiceUtil or the ServiceLocator?
Where is the bean ‘hr.vipnet.web.pricingservice.PricingService’ located? Can you describe your package layout?
Regards,
Bert
February 10th, 2011 at 15:59
Hi Bert,
Thanks for you replay.
I’m consuming the service using ServiceLocator.
First exception is when i’m “locating” hr.vipnet.web.pricingservice.PricingService using ServiceLocator and second one hr.vipnet.web.pricingservice.PricingServiceUtil.
hr.vipnet.web.pricingservice.PricingService is equivalent to HelloWorldService
Br,
Alan
February 17th, 2011 at 11:07
Hi Bert,
Thanks for your fantastic Article!
I still don’t get why do we need the base class HelloWorldServiceBaseImpl, nor why do we inject a bean there. The HelloWorldServiceImpl does not make use of this “_helloWorldService”?
I also don’t get why HelloWorldServiceBaseImpl extends PrincipalBean. It doesn’t seem that we use it at all?
March 11th, 2011 at 16:14
Hi Bert,
I can’t make it work, I have a service implementation which uses hibernate and I get the “Service XXXX not set”, but when I deploy the service implementation I see no error in server logs
so I tried changing
com.liferay.portal.kernel.spring.context.PortletContextLoaderListener
in web.xml with:
org.springframework.web.context.ContextLoaderListener
but I get an Hibernate Exception:
HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Regards, Enzo
PS: sorry, my english is awful ¬¬
March 11th, 2011 at 16:18
sorry, I meant:
[listener]
[listener-class]com.liferay.portal.kernel.spring.context.PortletContextLoaderListener[/listener-class]
[/listener]
and
[listener]
[listener-class]org.springframework.web.context.ContextLoaderListener[/listener-class]
[/listener]
respectively
Best Regards, Enzo
May 27th, 2011 at 19:21
I’ve been able to implement this example successfully. However, when I try to do something meaningful in my service impl like access web services through Spring’s JAX-WS org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean I can find no way to make it work. It seems that Spring can never find the WS interfaces/stubs in the Liferay runtime environment even though everything works in Maven tests. I’ve put the stubs in the service impl as a jar, as java source, in the lib\ext, in the portlet, everywhere, etc and no luck. Anybody had success doing this?
May 31st, 2011 at 17:59
I think I found why this didn’t work for me. I am using LR 5.2 EE SP3 on Tomcat 6 which has a classloader bug: “ClassLoaderProxy does not work with Tomcat 6. This prevents a plugin portlet from using the services of another
plugin.” – http://www.liferay.com/community/forums/-/message_boards/message/4720789
June 14th, 2011 at 13:59
Yes, that’s what you get when you post tutorials – questions over questions over issues over more issues
Nice one!
July 4th, 2011 at 03:25
Hello,
After I created liferay-plugin-package.properties with the following content:
name=Hello World Service Implementation
module-group-id=nl.devatwork.service.impl
module-incremental-version=1
short-description=
change-log=
page-url=http://www.devatwork.nl
author=Dev @ Work
licenses=Free
portal-dependency-jars=hello-world-service-1.0.0-SNAPSHOT.jar
and execute mvn clean package,
It thrown the following exception:
$ mvn clean package
[INFO] Scanning for projects…
[WARNING]
[WARNING] Some problems were encountered while building the effective model for nl.devatwork.hello.world:hello-world-service-impl:war:1.0.0-SNAPSHOT
[WARNING] ‘build.plugins.plugin.version’ for org.apache.maven.plugins:maven-compiler-plugin is missing. @ nl.devatwork.hello.world:hello-world-application:1.0.0-SNAPSHOT, C:\work\hello-world-start\pom.xml, line 24, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] ————————————————————————
[INFO] Building Dev@Work Hello World Service Implementation 1.0.0-SNAPSHOT
[INFO] ————————————————————————
Downloading: http://localhost:8081/nexus/content/repositories/thirdparty/nl/devatwork/hello/world/hello-world-service/1.0.0-SNAPSHOT/maven-metadata.xml
[WARNING] Could not transfer metadata nl.devatwork.hello.world:hello-world-service:1.0.0-SNAPSHOT/maven-metadata.xml from/to thirdparty (http://localhost:8081/nexus/content/repositories/thirdparty): Error transferring file: Connection refused: connect
Downloading: http://localhost:8081/nexus/content/repositories/thirdparty/nl/devatwork/hello/world/hello-world-service/1.0.0-SNAPSHOT/maven-metadata.xml
[WARNING] Could not transfer metadata nl.devatwork.hello.world:hello-world-service:1.0.0-SNAPSHOT/maven-metadata.xml from/to thirdparty (http://localhost:8081/nexus/content/repositories/thirdparty): Error transferring file: Connection refused: connect
Downloading: http://localhost:8081/nexus/content/repositories/thirdparty/nl/devatwork/hello/world/hello-world-service/1.0.0-SNAPSHOT/hello-world-service-1.0.0-SNAPSHOT.pom
[INFO] ————————————————————————
[INFO] BUILD FAILURE
[INFO] ————————————————————————
[INFO] Total time: 3.684s
[INFO] Finished at: Mon Jul 04 11:15:50 EST 2011
[INFO] Final Memory: 3M/55M
[INFO] ————————————————————————
[ERROR] Failed to execute goal on project hello-world-service-impl: Could not resolve dependencies for project nl.devatwork.hello.world:hello-world-service-impl:war:1.0.0-SNAPSHOT: Failed to collect dependencies for [com.liferay.portal:portal-kernel:jar:5.2.8 (provided), com.liferay.portal:portal-service:jar:5.2.8 (provided), nl.devatwork.hello.world:hello-world-service:jar:1.0.0-SNAPSHOT (provided)]: Failed to read artifact descriptor for nl.devatwork.hello.world:hello-world-service:jar:1.0.0-SNAPSHOT: Could not transfer artifact nl.devatwork.hello.world:hello-world-service:pom:1.0.0-SNAPSHOT from/to thirdparty (http://localhost:8081/nexus/content/repositories/thirdparty): Error transferring file: Connection refused: connect -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
I am wonder how can I tell the mvn package build is on my project path, rather than going to grab it from my local repository ?
Thanks
Sam,
July 4th, 2011 at 08:34
Hello Sam,
I think you need to configure the dependency properly in your POMs, see http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html for details.
Bert
July 5th, 2011 at 02:11
An excellent tutorial, ever!
It works like a charm
July 5th, 2011 at 03:54
Bert,
How do you use Hibernate/JPA to in the HelloWorldService module? I want to use the service module to interact with mysql database, and then create a service facade for the client.
Thanks
Sam
July 5th, 2011 at 09:04
Hello Sam,
I haven’t done that before so I cant help you with that.
Good luck,
Bert
July 18th, 2011 at 03:02
Hello Bert,
Why is the PrincipalBean needed in this example?
eg.
HelloWorldServiceBaseImpl extends PrincipalBean
Another question, is the following annotation only way to create a reusable web service in liferay?:
@BeanReference(name = “nl.devatwork.hello.world.service.HelloWorldService.impl”)
Thanks
Sam
January 31st, 2012 at 11:19
Hi Birt,
Can you please post updates for the post to work in Liferay 6.0.6?
May 7th, 2012 at 10:51
[...] to implement resuable Custom Services without using ext and servicebuilder. I referred this article: http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-buil…l], but I am confused in how should I implement this using eclipse? Following are the steps that I [...]
November 26th, 2012 at 19:14
[...] provide any other service I would build a service with using service builder or ext, as described http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-build… Flag Please sign in to flag this as [...]
February 21st, 2013 at 09:26
Hi Bert!
Thanks for your articles, they are very helpful. I only managed to build a service with your example, and I haven’t got working Liferay service-builder generated project yet (although your sample is for 5x version and I use 6.1).
But the reason I need a service is that I want to implement my own search mechanisms. I guess you aware of fact that Liferay dynamic queries have lack of functionality, especially when dealing with many-to-many relations. Have you ever used custom SQL queries in your services? If you shared some examples, that would be just great.
Again, thanks for your blog!