Creating OData Service for HANA Cloud Platform JPA based Web Application and extend OData processing using custom logic
1. Introduction
This blog describes configuration and implementation steps to expose a new OData Service based on a JPA entity and run the service as an Hana Cloud Java Application. Apache Olingo is a Java library that implements the Open Data Protocol (OData). Apache Olingo serves client and server aspects of OData. It currently supports OData 2.0 for JPA Entities. Blog also provide the way where you can provide custom pre/post processes for different type Requests on OData Services to various use cases.
For more details:
What is the Open Data Protocol (OData)? http://www.odata.org/
Why does SAP prefer OData as connectivity?
These two SCN blogs motivates the reasons why SAP prefers to use OData as connectivity:
2. Prerequisite Activities
2.1 Create and build JPA Project
Web Project is already developed with JPA Entity to consume HANA Cloud Platform Database (HANA or MaxDB). Project should have persistence.xml and class files for JPA entities as shown in below picture.
If you don’t have any Java JPA Project. You can have one from attach file (JobEnrollmentDemo.zip).
2.2 Get dependent library
Add Following maven dependencies in project pom.xml to include OData Olingo and Apache CXF Jars
dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-api</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-core</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-jpa-processor-api</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-api-annotation</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-jpa-processor-core</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>2.7.5</version>
</dependency>
3. Configuration and Implementation
3.1 Configure persistence.xml in JPA model
Open persistence.xml file from <ProjectName>/Java Resources/src/META-IN and Add the following red-marked <property> line to the persistence.xml file
property name=“eclipselink.jpql.parser” value=“org.eclipse.persistence.queries.ANTLRQueryBuilder”/>
3.2 Create required Java Classes
3.2.1 Create Factory class for Managing Connection with Database using Server Context (eg. JpaEntityManagerFactory.java)
3.2.2 Create new Java class by extending ODataJPAServiceFactory to provide means for initializing Entity Data Model (EDM) Provider and OData JPA Processors.
3.3 Configure web descriptor file (web.xml)
Configure the web application as shown below by adding the following servlet configuration to web.xml.
The Service factory (eg. LMSApprovalServiceFactory) which was implemented is configured in the web.xml of the ODataApplication as
one of the init parameters.
4. Testing OData Service
Publish and start web application (Contain JPA Entity) on HCP Account or local web server and Open the application URL and append recourse path provided in web.xml for accessing OData Service
Test Other OData operations using following tutorial
http://www.odata.org/getting-started/basic-tutorial/
5. Custom OData Processing
Most of the time in web project we need to provide custom pre and post processing with default OData processing like
- Adding additional filters or select filter to restrict usages of OData GET Request
- Manipulating results of GET Request
- Triggering some functionality in case of new Entity creation
- Filled non-provided data for Entity.
5.1 Create Custom JPA Processor for OData Request
Extend default implement class org.apache.olingo.odata2.jpa.processor.core.ODataJPAProcessorDefault for OData Processing handling with your own Custom Processor Class like eg. class CustomoDataJPAProcessor in following screen shot. and override method for different operations on case by case basis
5.1.1. Override readEntitySet Method for extending GET request to get entitySet as return – The instance variable jpaProcessor can be used to process the OData request. The jpaProcessor returns the JPA entities after processing the OData request.
5.1.2. Override readEntity method for extending GET request to get single record for entity as return – Same processing like above method
5.1.3. Override createEntity method for extending POST request to create new record for entity – create private method to manipulate entity record and add any additional processing
You can check other method in default JPA Processor class ODataJPAProcessorDefault
5.2 Changing reference from default JPA Processing with Custom Processing Class.
Write a Custom OData JPA Service Factory. Implement an OData JPA service factory to create an OData service with custom OData JPA Processor. The default service factory org.apache.olingo.odata2.jpa.processor.api.ODataJPAServiceFactory part of the library cannot be used. Hence, create a class by extending org.apache.olingo.odata2.api.ODataServiceFactory. Follow the steps below to hook an existing flow to a custom OData JPA Processor. Copy the entire code from ODataJPAServiceFactory and replace the code as shown below.
ODataSingleProcessor odataJPAProcessor = accessFactory.createODataProcessor(oDataJPAContext);
with
ODataSingleProcessor odataJPAProcessor = new CustomODataJPAProcessor(oDataJPAContext);
5.3 Use CustomODataServiceFactory for extending your service factory class instead of using default ODataJPAServiceFactory
Change extension for class created in step 3.2.
Hope this blog will help you to expose you HCP/Java Web applications using OData based protocol which can be easily be consumed by your UI5 application and other middleware like HANA Cloud Integration.
Dear Vijay Singh Rajput,
I'm also learning Olingo and I have successfully deployed my project on local serve with MySQL database. The Odata service worked well.
But when I tried to deploy my project on HCP trial with the default HANA DB. The Odata Service always failed. The following error occured:
HTTP Status 500 - Servlet.init() for servlet ODataServlet threw exception
I checked the log but I can't find why this happened. I think it's related with persistence unit configuration.
I tried every configuration in persistence.xml but none of them worked.
Would you please tell me how to configure the persistence unit when deploying on HCP trial?
Thanks and best regards,
Jerry.Lu
Hi Jerry,
I have used EclispeLink 2.5 to connection using persistence.xml (Persistence Provider: org.eclipse.persistence.jpa.PersistenceProvider)
Regards,
Vijay
Hi Vijay,
Thanks for your reply. I have solved this problem by changing the application configuration.
Thanks for your blog. It gives me a lot of instruction.
Regards,
Jerry
Hi Jerry,
I am facing the same error, can you please let me know what application configurations you made??
Your help is much appreciated!!
Thanks,
Madhukar
Hi Madhukar,
I changed the runtime to "Java Web Tomcat 7" and it worked.
Hope it helps.
Best regards,
Jerry.Lu
Hi Vijay,
I get the following error, request you to kindly help me out with
Servlet in web application threw load() exceptions
java.lang.ClassNotFoundException:
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
Regards,
Madhuri
Hi Madhuri,
As per error, it seems like you have not defined some dependency in project.
For Class :org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
you need following maven dependency
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>2.7.5</version>
</dependency>
Hope this will help you.
Regards,
Vijay
Hi Vijai
Very good document, Have the project in eclipse for analysis ?.
Regards,
Diego
Hi Vijai,
Did you use Spring in this demo project, if so, will you please kindly guide me how to configure in applicationContext.xml, my scenario almost like yours, used JPA and Olingo thanks in advance!
Regards,
Bryan
Hi Bryan,
Not yet, but I am planning to do it soon. Will update you once I will complete with it.
Regards,
Vijay
Thanks.
Hi Vijay,
Could you please help? In the section "5.2 Changing reference from default JPA Processing with Custom Processing Class", I created a class CustomODataJPAServiceFactory extends ODataServiceFactory. I called the function initializeODataJPAContext() in the createService(final ODataContext ctx), and i got an error:
Cannot resolve methodinitializeODataJPAContext()
Thanks,
Toan
Hi All,
I am new to OLingo and what I see in this tutorial is
<servlet-mapping>
<servlet-name>ODataServlet</servlet-name>
<url-pattern>/ApprovalList.svc/*</url-pattern>
</servlet-mapping>
I did not find any code for the ODataServlet here.
So how are we mapping it to the url?
Please guide
Hi Priya,
From my understanding, this servlet (configured in web.xml) will map with org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet. All request which includes /ApprovalList.svc/ in URL will call the standard class.
hope this would be helpful!
Regards,
Bryan
Fantastic!!
Would you be able to advise and provide example on JTA instead of local_resouces?
I've tried the above example but it says
javax.servlet.ServletException: java.lang.IllegalStateException:
Exception Description: Cannot use an EntityTransaction while using JTA.
Would appreciate if you could able to help
Unless you are asking for clarification/correction of some part of the Document, please create a new Discussion marked as a Question. The Comments section of a Blog (or Document) is not the right vehicle for asking questions as the results are not easily searchable. Once your issue is solved, a Discussion with the solution (and marked with Correct Answer) makes the results visible to others experiencing a similar problem. If a blog or document is related, put in a link. Read the Getting Started documents (link at the top right) including the Rules of Engagement.
NOTE: Getting the link is easy enough for both the author and Blog. Simply MouseOver the item, Right Click, and select Copy Shortcut. Paste it into your Discussion. You can also click on the url after pasting. Click on the A to expand the options and select T (on the right) to Auto-Title the url.
Thanks, Mike (Moderator)
SAP Technology RIG
I can't see the JobEnrollmentDemo.zip archive.. Thanks Ritin
Thank you for shaing this, you're a rockstar!
I am really interested in going through this tutorial but I also cannot find the JobEnrollmentDemo.zip anywhere. Is this project hosted on Github or are you able to share a download link on mdocs in the comments?
Thank you again, really appreciate your work!
-Austin
Where can I download the JobEnrollmentDemo project?
Hi Vijay,
Thanks for the blog, I followed everything but I am unable to go beyond step 3, when I try testing the ODATA service, I get error: [http-nio-8080-exec-2] INFO org.apache.cxf.endpoint.ServerImpl - Setting the server's publish address to be /
Any suggestions what needs to be changed/added?