In this article , I am going to write about how to consume data from a third-party Restful Webservice in Adobe Experience Manager. I am fetching live cricket score from Cricinfo using their XML data with the help of org.apache.http package.
Steps to consume Restful web service -
1.Create and Setup Maven project
2.Create and compile Java classes that performs the Restful request.
3.Build and deploy OSGi bundle to Adobe CQ
4.Create template and component to display web service response in webpage.
Create and Setup Maven Project
By performing below steps we can create an Adobe CQ archetype project
i.Open cmd prompt and go to working project folder
ii.Execute Maven script to create project folders
mvn archetype:generate -DarchetypeRepository=http://repo.adobe.com/nexus/content/groups/public/ -DarchetypeGroupId=com.day.jcr.vault -DarchetypeArtifactId=multimodule-content-package-archetype -DarchetypeVersion=1.0.2 -DgroupId=my-group-id -DartifactId=myproject -Dversion=1.0-SNAPSHOT -Dpackage=com.mycompany.myproject -DappsFolderName=myproject -DartifactName="My Project" -DcqVersion="5.6.1" -DpackageGroup="My Company"
mvn eclipse:eclipse
iii.After executing this script , we can import this project into Eclipse.
Create and Compile required Java files
Add the following Java files to the com.mycompany.myproject package:
- A Java interface named Cricketscore.
- A Java class named CricketscoreImpl that extends the Cricketscore interface under impl folder.
Create and Setup Maven Project
iii.After executing this script , we can import this project into Eclipse.
Create and Compile required Java files
Create and Compile required Java files
Add the following Java files to the com.mycompany.myproject package:
- A Java interface named Cricketscore.
- A Java class named CricketscoreImpl that extends the Cricketscore interface under impl folder.
Cricketscore.java
package com.mycompany.myproject; public interface Cricketscore { //Returns array data that represents the live score updates public String[] getLivescore(); }
CricketscoreImpl.java
In this development article , we used the Apache HttpClient library which simplifies handling HTTP request.
We can retrieve and send data via the HttpClient class.An instance of this class can be created with new DefaultHttpClient().The HttpClient uses a HttpUriRequest to send and receive data.Important subclass of HttpUriRequest are HttpGet and HttpPost. By using HttpGet, we are getting response from http://static.cricinfo.com/rss/livescores.xml
We can get the response of the HttpClient as an InputStream. So below lines of code used to get response from service and by using BufferedReader & InputStreamReader we are processing that response to get XML data as String.
DefaultHttpClient httpClient = new DefaultHttpClient(); HttpGet getRequest = new HttpGet("http://static.cricinfo.com/rss/livescores.xml"); getRequest.addHeader("accept", "application/xml"); HttpResponse response = httpClient.execute(getRequest); if (response.getStatusLine().getStatusCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode()); } BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent()))); String score; String xmldata="" ; while ((score= br.readLine()) != null) { xmldata= myJSON + score; } httpClient.getConnectionManager().shutdown();
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xmldata)); Document doc = db.parse(is); NodeList nodes = doc.getElementsByTagName("item"); String[] titles = new String[nodes.getLength()]; // iterate the nodes for (int i = 0; i < nodes.getLength(); i++) { Element element = (Element) nodes.item(i); NodeList name = element.getElementsByTagName("title"); Element titlexml = (Element) name.item(0); title =getCharacterDataFromElement(titlexml); titles[i]=title; } return titles;Here is the all lines of code for CricketscoreImpl.java
package com.mycompany.myproject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import javax.xml.parsers.*; import org.xml.sax.InputSource; import org.w3c.dom.*; import java.io.*; import java.util.*; //This is a component so it can provide or consume services @Component @Service public class CricketscoreImpl implements Cricketscore { protected final Logger log = LoggerFactory.getLogger(this.getClass()); @Override public String[] getLivescore() { // TODO Auto-generated method stub try { String title = ""; DefaultHttpClient httpClient = new DefaultHttpClient(); HttpGet getRequest = new HttpGet("http://static.cricinfo.com/rss/livescores.xml"); getRequest.addHeader("accept", "application/xml"); HttpResponse response = httpClient.execute(getRequest); if (response.getStatusLine().getStatusCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode()); } BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); String myXMLdata = ""; String output; while ((output = br.readLine()) != null) { myXMLdata = myXMLdata + output; } httpClient.getConnectionManager().shutdown(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(myXMLdata)); Document doc = db.parse(is); NodeList nodes = doc.getElementsByTagName("item"); String[] titles = new String[nodes.getLength()]; for (int i = 0; i < nodes.getLength(); i++) { Element element = (Element)nodes.item(i); NodeList name = element.getElementsByTagName("title"); Element line = (Element)name.item(0); title = getCharacterDataFromElement(line); titles[i] = title; } return titles; } catch (Exception e) { e.printStackTrace() ; } return null; } public static String getCharacterDataFromElement(Element e) { Node child = e.getFirstChild(); if (child instanceof CharacterData) { CharacterData cd = (CharacterData) child; return cd.getData(); } return ""; } }
Next we need to add the Apache HttpComponents dependency in Maven POM file located at bundle folder in created project. So add below lines in POM.xml before end of </dependencies>.
<
dependency
>
<
groupId
>org.apache.httpcomponents</
groupId
>
<
artifactId
>httpclient</
artifactId
>
<
version
>4.1.1</
version
>
</
dependency
>
Build and deploy the OSGi bundle using Maven
Follow below steps to build the OSGi component,
i.Navigate to pom.xml located folder , then hold ctrl + shift then right-click to open cmd prompt from that folder
ii. Execute the maven command : mvn clean install
iii.After successful build, we can find OSGi bundle at (project folder)\bundle\target
iv.To deploy this bundle, open Apache Felix Console (http://server:port/system/console/bundles )
v. In bundles tab, browse and install the created bundle under (project folder)\bundle\target
vi.After installing, reload and check bundle status must be Active.
To display the webservice response , we need to follow below steps
Open (http://server:port/system/console/bundles ) and create project as per below structure
Create a template and Component
To display the component in page we need template, so first we will create a template ,
2. Enter required information to create basic component and name the component as livescore
3. Open livescore.jsp and paste below code to display Live Create Score
<@include file="/libs/foundation/global.jsp"> <cq:includeclientlib categories="jquerysamples"></cq:includeclientlib> <html> <head> <!-- Below script used to reload page <script> $(document).ready(function(){ setInterval(function(){cache_clear()},60000); }); function cache_clear() { window.location.reload(true); } </script> --> <style> #page-wrap { width: 800px; margin: 0 auto; border: 3px solid #73AD21; padding: 10px; background-image: linear-gradient( to right, #0896A8, #0896A8 15%, #0896A8 15%, #82C8D1 50%, #82C8D1 50% ); } </style> <% com.mycompany.myproject.Cricketscore cs = sling.getService(com.mycompany.myproject.Cricketscore.class); String[] xmldata= cs.getLivescore() ; request.setAttribute("xmldata", xmldata); %> <body> <div id="page-wrap"> <h3> Live Cricket Score Feed from CRICINFO</h3> <hr /> <c:foreach items="${xmldata}" var="xmldatascore"> <c:if test="${not empty xmldatascore}"> <strong><c:out value="${xmldatascore}"></c:out></strong><hr /> </c:if> </c:foreach> </div> </body> </head> </html>
In above code, i have added jquery to refresh the page for every 60 secs so include jquerysample Client libraries
Create the web page to display Live Cricket Score from Cricinfo that based on the above created template.
It is giving this error
ReplyDeleteAn error occurred at line: 33 in the jsp file: livescore.jsp
cannot be resolved
30: );
31: }
32: </style>
33: <%
34: com.adobe.restservice.impl.CricketscoreImpl cs = sling.getService(com.adobe.restservice.impl.CricketscoreImpl.class);
35: String[] xmldata= cs.getLivescore() ;
36: request.setAttribute("xmldata", xmldata);
An error occurred at line: 33 in the jsp file: livescore.jsp
Syntax error on tokens, delete these tokens
30: );
31: }
32: </style>
33: <%
34: com.adobe.restservice.impl.CricketscoreImpl cs = sling.getService(com.adobe.restservice.impl.CricketscoreImpl.class);
35: String[] xmldata= cs.getLivescore() ;
36: request.setAttribute("xmldata", xmldata);
An error occurred at line: 33 in the jsp file: livescore.jsp
Syntax error on tokens, delete these tokens
30: );
31: }
32: </style>
33: <%
34: com.adobe.restservice.impl.CricketscoreImpl cs = sling.getService(com.adobe.restservice.impl.CricketscoreImpl.class);
35: String[] xmldata= cs.getLivescore() ;
36: request.setAttribute("xmldata", xmldata);
Did you check your bundle is in active mode?
DeleteYou can download its package from https://github.com/Naveeng45/AEMTechDevBlog
ReplyDeleteIf you still facing any issues, let me know.
Hi Naveen,
ReplyDeleteThis is great stuff!!!
Few minor changes on jsp level to remove run time errors.
1. <%@include file="/libs/foundation/global.jsp"%>
2.
3. to
Thanks
Hi Naveen,
ReplyDeleteWe can also call rest api through java script. why to use osgi bundle to interact with third party rest api. which is best way to call rest api. Can you please help
Thanks,
HArsh
Hi Harsh,
DeleteYeah we can call Rest api via JS but sometimes Api output would be in raw object so we need to process it to display in page , in that scenario we would use OSGi bundle to consume. Sometimes the output of Api is in desired format then we need to think about performance to make the call. If we call it through JS, then it will load every time the page loads and every user request. Some apis would have performance impact if many hits happen simultaneously.In such scenarios we can use OSGi to cache the api response in dispatcher.So that it doesnt hit the api everytime and instead serves from cache.This wont be applicable if the data is very dynamic and cannot be cached. So consuming Rest APi through OSGi is best way.
Thanks,
Naveen