Liferay 7 REST Webservices Tutorial
Liferay 7 REST Web services Tutorial for creating Jersey REST web services using OSGI.Liferay Service builder has capability to auto create JSON REST services, but still there are some pros and cons of using it and explained in the below tutorial:
Liferay 6 Jersey REST Integration Tutorial
Jersey Integration in liferay is easy as in other framework and this tutorial will drive you on how to create web services using jersey framework. Liferay out of the box provides axis engine framework for SOAP and JSON web services.READ MORE
Installations:
- Liferay Eclipse Neon IDE 3.1.0 M1 : Click here to download
- Liferay CE Portal tomcat GA3 :
- Jersey
OSGI Component offers Jersey Application as bridge to create REST service and which make easy for us create REST services on the fly than the service builder. Liferay 7 IDE has REST Template project creation to easy the development.
Let’s Jump into tutorial and If you are new to REST then click here to access complete REST tutorials to understand basics. As explained in this tutorial: Liferay 7 Portlet Tutorial – Part2 , we will use the leave application to create REST API. The new project structure would be follows as:
- leave-core-services : This module offers business layer using service builder
- leave-web : This module will be used for web layer
- leave-rest : This module is used to expose REST API
Liferay 7 REST Example:
- Liferay latest IDE providing REST Project template. We will create REST Component Projec, so In Eclipse, click File -> New Liferay Module Project. Select Project Template as “REST”
- Provide Component class name and package path. This package path is added to Bundle Symbolic
Name - bnd.bnd template file is:
-
Bundle-Name: leave-rest Bundle-SymbolicName: org.javasavvy.leave.rest Bundle-Version: 1.0.0 ConfigurationPath: /configuration Include-Resource: configuration=src/main/resources/configuration
-
- update gradle dependencies with below and run the gradle build task. Refresh the gradle project again to affect the dependency changes (Right click on project -> Select Gradle -> Select Gradle Refresh)
-
dependencies { compileOnly group: "javax.ws.rs", name: "javax.ws.rs-api", version: "2.0.1" compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0" compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0" compileOnly group: "com.liferay.portal", name: "com.liferay.util.java", version: "2.0.0" compileOnly group: "com.liferay.portal", name: "com.liferay.portal.impl", version: "2.0.0" compileOnly project(":modules:leave-core:leave-core-api") compileOnly project(":modules:leave-core:leave-core-service") }
-
- leave-rest project structure is:
- RESTExtenderConfiguraiton: What is REST Extender configuration?? OSGI is running in JVM container as OSGI container holds object,services etc. How OSGI will detect REST Context paths??
- REST Extenders will track the services in the OSGI on specified end points. REST Extenders are need to publish API over the contextPaths, which need to be specified in RESTExtenderConfiguration file.
-
contextPaths=/leave-rest
- CXFPublisherEndpointPublisherConfiguration
-
contextPath=/leave-rest authVerifierProperties=auth.verifier.PortalSessionAuthVerifier.urls.includes=*
-
- Liferay creates REST Component with sample methods, so edit the LeaveRestComponent class that returns Leave objects as JSON
-
@ApplicationPath("/leave") @Component(immediate = true, service = Application.class) public class LeaveRestControllerApplication extends Application { public Set<Object> getSingletons() { return Collections.<Object>singleton(this); } private LeaveLocalService leaveLocalService; @Reference(unbind="-") public void setLeaveLocalService(LeaveLocalService leaveLocalService){ this.leaveLocalService=leaveLocalService; } @GET @Path("/morning") @Produces("text/plain") public String hello() { return "Good morning!"; } @GET @Path("/leave-info/{leaveId}") @Produces(MediaType.APPLICATION_JSON) public String getLeave(@PathParam("leaveId") long leaveId){ Leave leave = null; Status status = new Status(); String jsonString = null; System.out.println("leave-info invodked"); try { leave = leaveLocalService.getLeave(leaveId); jsonString = JSONFactoryUtil.serialize(leave); } catch (Exception e) { if(e instanceof NoSuchLeaveException) { status.setMessage("NO Leave Entity Found"); status.setStatus(250); jsonString = JSONFactoryUtil.serialize(status); } e.printStackTrace(); } return jsonString; } }
-
- run deploy gradle task and deploy the OSGI container.
What next?? Liferay loads REST Extender configuration and creates REST resources, but some times if you access REST URL,it may give 404 error. We need to manually create REST Extender configuration in Control panel or update existing configuration.
Liferay REST Extender Configuration :
In this step, we need to update REST Extender configuration in the control panel section of admin
- Click on Control Panel -> Configuration -> System Settings
- Search for REST
- Click on REST Extender
- You can see that rest extender configuration will be already created.so just update this config again.
- Click on the configuration and you can see the deployed OSGI module “leave-rest” with specified context paths. Click + icon if any additional context paths required.
- Click on update and access the web services in the url :http://localhost:8080/o/leave-rest/leave/morning
- Liferay 7 starts with context /o unlike in Liferay 6 with /c
- Hope you have the entry created already with leave-web application and access the leave info with leave Id.
- http://localhost:8080/o/leave-rest/leave/leave-info/1
- RESPONSE:
-
{"javaClass":"org.javasavvy.leave.model.impl.LeaveImpl","serializable": {"leaveName":"Pongal Vacation","new":false,"originalUuid":"f15abe58-d0e4-cccd-77dc-a556b4e7e678","columnBitmask":0, "setOriginalUserId":false,"endDate":{"javaClass":"java.util.Date","time":1484697600000},"cachedModel":true, "groupId":20143,"userName":"Test Test","uuid":"f15abe58-d0e4-cccd-77dc-a556b4e7e678","userId":20156, "originalCompanyId":20116,"escapedModel":null,"setOriginalGroupId":false,"companyId":20116,"setModifiedDate":false, "originalGroupId":20143,"setOriginalCompanyId":false,"modifiedDate":{"javaClass":"java.util.Date","time":1485951753553}, "originalUserId":20156,"leaveId":1,"startDate":{"javaClass":"java.util.Date","time":1484092800000}, "createDate":{"javaClass":"java.util.Date","time":1485951753537}}}
Click here to Download Liferay 7 REST code
-
7 thoughts on “Liferay 7 REST Webservices Tutorial”
Comments are closed.
Hi,
Thanks for wonderful tutorial.
I have developed few Rest APIs on Liferay 7.
They work fine.
However the only problem is they do not require any authentication (just like /api/jsonws requires). How can I add liferay authentication to these custom Rest APIs
Hi, I am looking for the exact same thing, could you manage to solve it?
Hi,
There is no “rest extender configuration” under System settings of Liferay Control Panel. I searched it… But it’s not present.
How can I get, any idea…
I am having Liferay7.0 GA4 CE
How I identify which user called web service? Thanks
Hi when i deploy the attached rest code i am facing given below error
org.apache.cxf.service.factory.ServiceConstructionException
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:219)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator.registerApplication(CXFJaxRsServiceRegistrator.java:100)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator.registerApplications(CXFJaxRsServiceRegistrator.java:110)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator.rewire(CXFJaxRsServiceRegistrator.java:130)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator._addApplication(CXFJaxRsServiceRegistrator.java:148)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator._swapClassLoader(CXFJaxRsServiceRegistrator.java:213)
at com.liferay.portal.remote.rest.extender.internal.CXFJaxRsServiceRegistrator.addApplication(CXFJaxRsServiceRegistrator.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.felix.dm.InvocationUtil.invokeMethod(InvocationUtil.java:111)
at org.apache.felix.dm.InvocationUtil.invokeCallbackMethod(InvocationUtil.java:66)
at org.apache.felix.dm.impl.ComponentImpl.invokeCallbackMethod(ComponentImpl.java:769)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.invoke(ServiceDependencyImpl.java:709)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.invoke(ServiceDependencyImpl.java:1160)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.invokeAdded(ServiceDependencyImpl.java:1114)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.doAddedService(ServiceDependencyImpl.java:858)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.access$200(ServiceDependencyImpl.java:60)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl$4.run(ServiceDependencyImpl.java:317)
at org.apache.felix.dm.impl.SerialExecutor.runTask(SerialExecutor.java:137)
at org.apache.felix.dm.impl.SerialExecutor.runTasks(SerialExecutor.java:119)
at org.apache.felix.dm.impl.SerialExecutor.execute(SerialExecutor.java:85)
at org.apache.felix.dm.impl.SerialExecutor.execute(SerialExecutor.java:104)
at org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl.addedService(ServiceDependencyImpl.java:314)
at org.apache.felix.dm.tracker.ServiceTracker$Tracked.customizerAdded(ServiceTracker.java:1331)
at org.apache.felix.dm.tracker.AbstractTracked.trackAdding(AbstractTracked.java:290)
at org.apache.felix.dm.tracker.AbstractTracked.track(AbstractTracked.java:236)
at org.apache.felix.dm.tracker.ServiceTracker$Tracked.serviceChangedHideAspects(ServiceTracker.java:1212)
at org.apache.felix.dm.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:1107)
at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:109)
at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:917)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:862)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:127)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:225)
at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:464)
at org.apache.felix.scr.impl.manager.AbstractComponentManager$3.register(AbstractComponentManager.java:886)
at org.apache.felix.scr.impl.manager.AbstractComponentManager$3.register(AbstractComponentManager.java:873)
at org.apache.felix.scr.impl.manager.RegistrationManager.changeRegistration(RegistrationManager.java:132)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:940)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:740)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.enableInternal(AbstractComponentManager.java:674)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:429)
at org.apache.felix.scr.impl.manager.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:657)
at org.apache.felix.scr.impl.BundleComponentActivator.initialEnable(BundleComponentActivator.java:341)
at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:403)
at org.apache.felix.scr.impl.Activator.access$200(Activator.java:54)
at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:278)
at org.apache.felix.utils.extender.AbstractExtender.createExtension(AbstractExtender.java:259)
at org.apache.felix.utils.extender.AbstractExtender.modifiedBundle(AbstractExtender.java:232)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:482)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:232)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:444)
at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:905)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:165)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:75)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:67)
at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:102)
at org.eclipse.osgi.container.Module.publishEvent(Module.java:461)
at org.eclipse.osgi.container.Module.start(Module.java:452)
at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:402)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1258)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1230)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:512)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:361)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:312)
Caused by: org.apache.cxf.service.factory.ServiceConstructionException: There is an endpoint already running on /leave.
at org.apache.cxf.jaxrs.JAXRSBindingFactory.addListener(JAXRSBindingFactory.java:86)
at org.apache.cxf.endpoint.ServerImpl.start(ServerImpl.java:123)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:206)
Can you please provide the POST webservie example