Jetty Web Server Java POJO Communication
In last tutorial you saw how to create Jetty Web server integrated with Google Proto Buffers. In this example you will see how to communicate with Java Old Plain Object means we will be sending request in Java Object and send response back to then client in Java Object. All configuration is same as previous tutorial
Tools needed:
- Eclipse latest version
- JDK 1.8
- Google Protocol Buffers exe which is already include in the project for download
- Maven 3.2.5
- Jetty dependent jars (already included in pom.xml)
- Create maven project name: JettyGoogleProtoBuffIntegration below is complete project structure:
- pom.xml:
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.javahonk.JettyGoogleProtoBuffIntegration</groupId> <version>1.0-SNAPSHOT</version> <artifactId>JettyGoogleProtoBuffIntegration</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <protobuf.version>2.6.1</protobuf.version> <protoc-jar.version>2.6.1.3</protoc-jar.version> <org.apache.log4j.version>2.1</org.apache.log4j.version> <org.springframework.version>4.1.5.RELEASE</org.springframework.version> <commons.logging.version>1.2</commons.logging.version> <apache.commons.lang.version>3.3.2</apache.commons.lang.version> <commons.collections.version>3.2.1</commons.collections.version> <junit.version>4.12</junit.version> </properties> <dependencies> <!-- Apache HTTP client --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.6</version> </dependency> <!-- google proto buff --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>2.6.1</version> </dependency> <!-- Jetty/Jersey dependency --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.8.8</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.8.8</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.2.9.v20150224</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.2.9.v20150224</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.5</version> </dependency> <!-- JUNIT --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!-- Spring --> <!-- Core utilities used by other modules. Define this if you use Spring Utility APIs (org.springframework.core.*/org.springframework.util.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Expression Language (depends on spring-core) Define this if you use Spring Expression APIs (org.springframework.expression.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Bean Factory and JavaBeans utilities (depends on spring-core) Define this if you use Spring Bean APIs (org.springframework.beans.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core, spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Application Context (depends on spring-core, spring-expression, spring-aop, spring-beans) This is the central artifact for Spring's Dependency Injection Container and is generally always defined --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Various Application Context utilities, including EhCache, JavaMail, Quartz, and Freemarker integration Define this if you need any of these integrations --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, and iBatis. (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you need ORM (org.springframework.orm.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Web application development utilities applicable to both Servlet and Portlet Environments (depends on spring-core, spring-beans, spring-context) Define this if you use Spring MVC, or wish to use Struts, JSF, or another web framework with Spring (org.springframework.web.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Support for testing Spring applications with tools such as JUnit and TestNG This artifact is generally always defined with a 'test' scope for the integration testing framework and unit testing stubs --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> </dependency> <!-- Spring Aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Spring Tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Spring JMS --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Log4j --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${org.apache.log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${org.apache.log4j.version}</version> </dependency> <!-- commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> </dependencies> </project>
- javahonk.properties:
#jetty server properties web.port=8080 #URLs javahonkTestPlainObject=/app/javahonk/testPlainObject
- server-context.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> <context:annotation-config /> <context:component-scan base-package="com.javahonk" /> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>javahonk.properties</value> </list> </property> <property name="ignoreUnresolvablePlaceholders" value="true"/> </bean> <bean class="com.javahonk.service.MessageHandler" /> <bean class="com.javahonk.service.JettyService" /> <bean id="jettyServer" class="org.eclipse.jetty.server.Server"/> <bean id="plainObjectProcessor" class="com.javahonk.adapter.PlainObjectProcessor"/> <bean id= "urlToAdaptorMap" class="java.util.HashMap"> <constructor-arg> <map key-type="java.lang.String" value-type="com.javahonk.adaptor.ServerMessageProcessor"> <entry key="${javahonkTestPlainObject}" value-ref="plainObjectProcessor" /> </map> </constructor-arg> </bean> </beans>
- AddressBook.java – Model class to send and receive data:
package com.javahonk.model; import java.io.Serializable; public class AddressBook implements Serializable { private static final long serialVersionUID = 1L; private String name; private String apartmentName; private String StreeName; private String city; private Integer zipCode; private String country; public AddressBook(String name, String apartmentName, String streeName, String city, Integer zipCode, String country) { this.name = name; this.apartmentName = apartmentName; StreeName = streeName; this.city = city; this.zipCode = zipCode; this.country = country; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getApartmentName() { return apartmentName; } public void setApartmentName(String apartmentName) { this.apartmentName = apartmentName; } public String getStreeName() { return StreeName; } public void setStreeName(String streeName) { StreeName = streeName; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Integer getZipCode() { return zipCode; } public void setZipCode(Integer zipCode) { this.zipCode = zipCode; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
- SerializeObject.java: To serialize and deserialize the object
package com.javahonk.model; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializeObject { public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException { try(ByteArrayInputStream b = new ByteArrayInputStream(bytes)){ try(ObjectInputStream o = new ObjectInputStream(b)){ return o.readObject(); } } } public static byte[] serialize(Object obj) throws IOException { try(ByteArrayOutputStream b = new ByteArrayOutputStream()){ try(ObjectOutputStream o = new ObjectOutputStream(b)){ o.writeObject(obj); } return b.toByteArray(); } } }
- JettyService.java: A jetty server class:
package com.javahonk.service; import javax.annotation.PostConstruct; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; public class JettyService { @Value("${web.port}") private int port; @Autowired private MessageHandler handler; @Autowired Server server; private static final Logger logger = LogManager.getLogger(MessageHandler.class.getName()); public void setPort(int port) { this.port = port; } public void setMessageHandler(MessageHandler handler) { this.handler = handler; } @PostConstruct public void init() throws Exception { logger.info("starting jetty server at port {}", port); ServerConnector connector = new ServerConnector(server); connector.setPort(port); server.setConnectors(new Connector[] { connector }); server.setHandler(handler); if (server.isRunning()) { logger.error("Jetty server already running."); } else { server.start(); } } }
- MessageHandler.java: Main class handles all request and send response:
package com.javahonk.service; import java.io.IOException; import java.util.Map; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import com.javahonk.adapter.ServerMessageProcessor; public class MessageHandler extends AbstractHandler { private static final Logger logger = LogManager.getLogger(MessageHandler.class.getName()); @Resource(name="urlToAdaptorMap") Map<String, ServerMessageProcessor> urlToAdaptorMap; public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.info("HTTP remote box- " + request.getRemoteAddr()); logger.info("HTTP request- " + request.getPathInfo()); String path = request.getPathInfo(); if (request.getMethod().equals(HttpMethod.POST)) { try { if (urlToAdaptorMap.containsKey(path)) { urlToAdaptorMap.get(path).handleRequest(request, response); response.setStatus(HttpServletResponse.SC_OK); } baseRequest.setHandled(true); } catch (Exception ex) { logger.error("Error :", ex); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } else { logger.warn("Received request on unsupported url {}", path); response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } }
- ServerMessageProcessor.java: Default interface for class implementation:
package com.javahonk.adapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public interface ServerMessageProcessor { public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ClassNotFoundException; }
- PlainObjectProcessor.java: A class where handler send request for processing and its process the request and send response back to the client:
package com.javahonk.adapter; import java.io.IOException; import java.util.List; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.javahonk.model.AddressBook; import com.javahonk.model.SerializeObject; public class PlainObjectProcessor implements ServerMessageProcessor { private static final Logger logger = LogManager.getLogger(PlainObjectProcessor.class.getName()); @SuppressWarnings("unchecked") public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ClassNotFoundException { byte[] message = IOUtils.toByteArray(request.getInputStream()); List<AddressBook> object = (List<AddressBook>) SerializeObject.deserialize(message); logger.info("Successfully parsed message {}", message); ServletOutputStream outputStream = response.getOutputStream(); outputStream.write(SerializeObject.serialize(object)); } }
- JavaHonkMainApp.java: Main class to start the application:
package com.javahonk; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class JavaHonkMainApp { private static final Logger logger = LogManager.getLogger(JavaHonkMainApp.class.getName()); private static String[] configLocation = {"server-context.xml"}; public static void main(String[] args) { logger.info("Starting JavaHonkMainApp..."); setUncaughtException(); ApplicationContext context = getApplicationContext(); registerShutdownHook(context); } private static void setUncaughtException() { Thread.currentThread().setUncaughtExceptionHandler((t, e) -> logger.error("Thread {} threw uncaught exception ", t.getName(), e)); } protected static ApplicationContext getApplicationContext() { return new ClassPathXmlApplicationContext(configLocation); } private static void registerShutdownHook(ApplicationContext context) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { logger.info("JavaHonkMainApp Exiting."); ((AbstractApplicationContext) context).close(); })); } }
- To start the applicatoin right click this class and run as java application you will out same as below:
- HTTPPostSendTestData.java: Client class which post data to the server and process response. Right click and run as java application to send and receive response:
package com.javahonk.test; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.HttpClientBuilder; import com.javahonk.model.AddressBook; import com.javahonk.model.SerializeObject; public class HTTPPostSendTestData { public static void main(String[] args) throws IOException, ClassNotFoundException { postHttpAsString("http://localhost:8080/app/javahonk/testPlainObject", buildDataFromObject()); } @SuppressWarnings("unchecked") private static void postHttpAsString(String url, byte[] message) throws ClassNotFoundException { try { HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost postRequest = new HttpPost(url); ByteArrayEntity entity = new ByteArrayEntity(message); entity.setContentType(MediaType.APPLICATION_OCTET_STREAM); postRequest.setEntity(entity); HttpResponse response = httpClient.execute(postRequest); if (response.getStatusLine().getStatusCode() != Response.Status.OK.getStatusCode()) { throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode()); } byte[] value = IOUtils.toByteArray(response.getEntity().getContent()); List<AddressBook> addressBook = (List<AddressBook>) SerializeObject.deserialize(value); addressBook.stream().forEach(address ->{ System.out.println(address.getName()); System.out.println(address.getApartmentName()); System.out.println(address.getStreeName()); System.out.println(address.getCity()); System.out.println(address.getZipCode()); System.out.println(address.getCountry()); }); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static byte [] buildDataFromObject() throws IOException{ List<AddressBook> addressBooks = new ArrayList<AddressBook>(); AddressBook addressBook = new AddressBook("JavaHonk", "55C", "John Steet", "Monroe", new Integer(8863), "USA"); addressBooks.add(addressBook); addressBooks.add(addressBook); return SerializeObject.serialize(addressBooks); } }
- You will below response data on console:
- That’s it. For more information you could visit this Google Protocol Buffer and Jetty Web Server.
Download source code: JettyJavaPlainObjectCommunication