In this post I will demonstrate how to configure CXF REST API in JPA implementation Hibernate on Karaf platform on JBoss fuse 7.4. I will use previous JPA project as code base to start the development. You can refer about it from my previous blog post.
Prerequisites
- You should have install java 1.8 or above.
- You should have IDE installed in your PC in my case I'm using IntelliJ IDEA.
- Your PC should setup Maven installed and configured.
- Your PC should install and setup SQLServer.
- Checkout base project from JPA project as code base.
Application module Dependency
First Lets add relevant dependencies in to Application POM file. Following is the full pom file content and updated part on bold font. Since we are using CXF REST we need to add relevant dependency for that.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>FuseHibernate</artifactId>
<groupId>com.fuse.hibernate.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Application</artifactId>
<name>OSGi Application</name>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>com.fuse.hibernate.example</groupId>
<artifactId>Service</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
<!-- CXF related dependencies -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.4.redhat-621084</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-services-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Private-Package>com.fuse.hibernate.example.app</Private-Package>
<Import-Package>com.fuse.hibernate.example.model,org.hibernate.jpa, org.apache.karaf.shell*;version="[4,5)", *</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
Defining the REST API END POINT
Then lets add our rest API end point. We just need add one class which we can define relevant methods we need to expose. For this example I will add GET,PUT,POST and DELETE methods in to our REST end point.
I will add "RestEndPoint " class in com.fuse.hibernate.example.app package with following content.
package com.fuse.hibernate.example.app;
import com.fuse.hibernate.example.model.Person;
import com.fuse.hibernate.example.service.PersonServiceImpl;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.math.BigInteger;
@Service
@Path("/personservice/")
public class RestEndPoint {
@Reference
private PersonServiceImpl personService;
static Logger LOG = LoggerFactory.getLogger(ExchangeProcessor.class);
@GET
@Path("/persons/{id}/")
@Produces("application/xml")
public Person getPerson(@PathParam("id") String id) {
LOG.info("----invoking getPerson, Person name is: " + id);
Person c = personService.findPerson(BigInteger.valueOf(Long.valueOf(id)));
return c;
}
@PUT
@Path("/persons/")
public Response updatePerson(Person person) {
LOG.info("----invoking updatePerson, Person name is: " + person.getName());
Person c = personService.findPerson(person.getId());
Response r;
if (c != null) {
personService.updateCustomer(person);
r = Response.ok().build();
} else {
r = Response.notModified().build();
}
return r;
}
@POST
@Path("/persons/")
public Response addPerson(Person person) {
LOG.info("----invoking addPerson, Person name is: " + person.getName());
Person saved=personService.createPerson(person);
return Response.ok().type("application/xml").entity(saved).build();
}
@DELETE
@Path("/persons/{id}/")
@Produces("application/xml")
public Response deletePerson(@PathParam("id") String id) {
LOG.info("----invoking getPerson, Person name is: " + id);
Person c = personService.findPerson(BigInteger.valueOf(Long.valueOf(id)));
Response r;
if (c != null) {
personService.removePersonById(c.getId());
r = Response.ok().build();
} else {
r = Response.notModified().build();
}
return r;
}
public PersonServiceImpl getPersonService() {
return personService;
}
public void setPersonService(PersonServiceImpl personService) {
this.personService = personService;
}
}
Defining the REST END POINT in BluePrint
Then lets add created rest endpoint class in to our BlurPrint.xml file in the Application module. We just need to modify following content which colored in bold.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:jpa="http://aries.apache.org/xmlns/jpa/v2.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">
<jpa:enable />
<tx:enable-annotations />
<service ref="personService" interface="com.fuse.hibernate.example.service.PersonService" />
<bean id="personService" class="com.fuse.hibernate.example.service.PersonServiceImpl" />
<bean
class="com.fuse.hibernate.example.app.ExchangeProcessor" id="exchangeProcessor">
<property name="personService" ref="personService"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint"
id="cbr-example-context" >
<route id="cbr-route" >
<from uri="file:work/cbr/input" />
<log message="Sending order ${file:name} to another country" />
<log id="logStatusIncident" message="OrderDetails Call ${body}"/>
<to uri="file:work/cbr/output/others" />
<convertBodyTo type="java.lang.String"/>
<process ref="exchangeProcessor"/>
<log message="${body}" />
</route>
</camelContext>
<jaxrs:server id="personsService" address="/crm">
<jaxrs:serviceBeans>
<ref component-id="personSvc"/>
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="personSvc" class="com.fuse.hibernate.example.app.RestEndPoint">
<property name="personService" ref="personService"/>
</bean>
</blueprint>
Now its ready to deploy application in to FUSE server.
Installing in to FUSE 7.4
We can use same set of commands except one new dependency addition code. In order to add dependencies first we have to run the fuse.bat file and then go to the console and enter following commands one by one. Only the third command new from previous post.
osgi:install -s mvn:com.microsoft.sqlserver/mssql-jdbc/7.4.1.jre8
osgi:install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-mssql/1.3.5
osgi:install -s mvn:org.apache.cxf/cxf-rt-rs-client/3.0.4.redhat-621084
Then lets install application by entering following commands one by one
feature:repo-add mvn:com.fuse.hibernate.example/Feature/1.0-SNAPSHOT/xml
feature:install osgi-customer-management-datasource
feature:install Model
feature:install Service
feature:install Application
Then after "list" command you should be able to see all the things we installed. Similar to below figure.
After Successful installation LIST command should return something similar to this. |
You can verify by accessing http://localhost:8181/cxf/ link you should be able to see following UI in browser.
http://localhost:8181/cxf/ output once successfully installed the Application |
Now you can click the WADL link and see the defined endpoints in there.
WADL output for defined REST service. |
Test the functionality
We can test the functionality by executing following commands in command prompt.
To Create new person
curl -X POST -T C:/Users/Person3.xml -H "Content-Type: text/xml" http://localhost:8181/cxf/crm/personservice/persons
You should get similar result as below figure and you can see Person table which inserted new value.
Command Line output of POST command |
Database Person table after executing above command |
To Get existing person
curl -X GET http://localhost:8181/cxf/crm/personservice/persons/1
Output of GET command |
To Update existing person
curl -X PUT -T C:/Users/Person4.xml -H "Content-Type: text/xml" http://localhost:8181/cxf/crm/personservice/persons
For this command you will not get any visible output but then if you run previous GET command you could see the Person details has been updated. As show on below figure.
Updated user details |
To Delete existing person
curl -X DELETE http://localhost:8181/cxf/crm/personservice/persons/1
For this command also you will not get any visible output on Command Line but after this if you run GET command then you could see you will not get any data. As show on below figure. Also you can check on database and see that Person already deleted from the database.
Deletion command output on Command Line |
Hi Nirmal,
ReplyDeleteThanks for the share all these steps, I checkout your code and updated the database details and try to install the application in fuse. Unfortunately I'm getting following error. Could you please help me on this ?
EventDispatcher: Error during dispatch. (javax.persistence.PersistenceException: [PersistenceUnit: persons] Unable to build Hibernate SessionFactory)
javax.persistence.PersistenceException: [PersistenceUnit: persons] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1016) ~[?:?]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:942) ~[?:?]
at org.hibernate.osgi.OsgiPersistenceProvider.createContainerEntityManagerFactory(OsgiPersistenceProvider.java:96) ~[?:?]
at org.apache.aries.jpa.container.impl.AriesEntityManagerFactoryBuilder.createAndPublishEMF(AriesEntityManagerFactoryBuilder.java:371) ~[?:?]
.
.
.
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The TCP/IP connection to the host CMP-061219DN16SQLEXPRESS01, port 1433 has failed. Error: "CMP-061219DN16SQLEXPRESS01. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall.".
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:234) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerException.ConvertConnectExceptionToSQLServerException(SQLServerException.java:285) ~[?:?]
at com.microsoft.sqlserver.jdbc.SocketFinder.findSocket(IOBuffer.java:2431) ~[?:?]
at com.microsoft.sqlserver.jdbc.TDSChannel.open(IOBuffer.java:656) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2472) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:2142) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1993) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1164) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnectionInternal(SQLServerDataSource.java:1108) ~[?:?]
at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnection(SQLServerDataSource.java:85) ~[?:?]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[?:?]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) ~[?:?]
at org.hibernate.resource.transaction.backend.jta.internal.DdlTransactionIsolatorJtaImpl.(DdlTransactionIsolatorJtaImpl.java:59) ~[?:?]
at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl.buildDdlTransactionIsolator(JtaTransactionCoordinatorBuilderImpl.java:46) ~[?:?]
at org.hibernate.tool.schema.internal.HibernateSchemaManagementTool.getDdlTransactionIsolator(HibernateSchemaManagementTool.java:175) ~[?:?]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:94) ~[?:?]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:183) ~[?:?]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72) ~[?:?]
at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:310) ~[?:?]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467) ~[?:?]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939) ~[?:?]
... 53 more
Is "CMP-061219DN16" your correct host name? Make sure you correctly mentioned it in your "feature.xml" file.
ReplyDeleteRefer to following URL https://kb.sos-berlin.com/pages/viewpage.action?pageId=17499564 for more details.
Also check following things
01) make sure your DB allow to authenticate by using username and passwords.
02) Configure correctly on SQL Server Configuration Manager