How to create REST micros-service using Apache Camel and Jetty - java

I have been experimenting with Apache Camel for creating a REST based micro services. Based on my experiments this is how I created an echo service with Jetty:
Maven
Included the following dependency in the Maven build:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
</dependency>
Java
Created a small route in Java which gets a request, converts it to a string, saves it to a file and then sends it back to the client:
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class EchoHttpServer {
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("jetty://http://localhost:8099/echo?httpMethodRestrict=POST")
.convertBodyTo(String.class)
.to("file://D:/work")
.process(exchange -> exchange.getOut().setBody(exchange.getIn().getBody()));
}
});
context.start();
}
}
Integration Test
This can then be tested using the Chrome extension Postman with which you can send a POST request which is then echoed by the reply:
Is this the recommended way to create REST based services with Apache Camel? Which are the potential problems of the approach taken above?

There are several ways how to expose a REST services with Camel.
Pure servet - this is what you already did. Seems to be quick and simple way (maybe too simple).
REST Camel endpoints (thanks noMad) http://camel.apache.org/restlet.html
In a container with a framework. My favourite is Apache Karaf with Camel-CXF . It takes more time to start, more memory to run, but frameworks allow additional features, such as authentication, auhtorization, logging, ..
If someone finds another way, please add an answer or comment, I am keen to find new options as well

Related

How to start a jax-rs server?

I have my endpoints like so:
#Path("/users")
public class Users {
private final SomeDependency dependency
public Users(SomeDependency dependency) {
this.dependency = dependency;
}
#GET
#Path("/{id}")
public Response Get(#PathParam("id") int id) {
User user = this.dependency.get(id);
return Response.ok(user).build();
}
}
Now how do I actually run a server with this endpoint?
I am confused about web servers/applications/servlets, using jersey jetty glassfish or whatever. Also web.xml files? what? ResourceConfigs only accept classes, not their instances. Everything seems to be such a mess.
How can I just do something similar to this?
public static void main(String[] args) throws Exception {
SomeDependency dependency = new SomeDependency();
Users usersEndpoint = new Users(dependency);
Server server = new Server();
server.registerEndpoint(usersEndpoint);
server.start();
}
Server
As far as the server goes, you have two types you have to consider: installed or embedded.
Installed
An installed server is one that is installed on your machine. For example, if you download Tomcat 10 and then follow the installation instruction, the server will get installed on your machine at whatever location you choose. In this situation, when you have an app (a war file) you are ready to deploy, you will copy it to your Tomcat server (to a specific location) and on server startup, Tomcat will see the application and then run it. The applications running in this type of environment will require a web.xml as they are deployed in a war file.
Embedded
An embedded server is one that is packaged into your jar application and is started in a main method just like any other Java SE application. Most installed servers also come with an embedded version. All you need to do is add the server dependencies into your application and then write the server configuration and startup (and shutdown) code. Applications running in this environment will not require a web.xml as they are deployed as a jar file.
Which one to use?
With the advancement and popularity of cloud services and microservices, many applications are moving towards embedded servers. The reason is that they are easy to deploy, are scalable, relatively lightweight, and applications become more self contained. There are many other pros that come with using embedded servers, but there are also some cons. Do your research before you make your final decision about which one you should use.
Example
If you want to quickly get started without having to worry about setting up the project, knowing what dependencies you need to add, adding the startup code, an easy way to get up and running is to use a Maven Archetype. If you go to the Jersey Docs, they get you started with an embedded Grizzly server running a Jersey application. What you need to do is run the following command from the command line (assuming you have Maven installed in your machine)
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example \
-DarchetypeVersion=2.33
If you read the docs I linked to, it will give an explanation of all that comes with the initial application. The main class will look like the following (with comments and imports omitted)
public class Main {
public static final String BASE_URI = "http://localhost:8080/myapp/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig().packages("org.example");
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
}
In this code, they use the packages() method of the ResourceConfig class that specifies a package for Jersey to scan for #Path and #Provider classes to register. In your case, if you don't need that, you can remove the method call. If you want to register your Users instance, all you do is call register(users) on the ResourceConfig.
See Also
What exactly is the ResourceConfig class in Jersey 2 - this link will help you get started with the ResourceConfig class and show you how you can register you resource classes or instances.
Other Frameworks
There are other frameworks out there that you may also want to consider
Dropwizard - Dropwizard is an opinionated framework built on top of Jersey. It uses an embedded Jetty as its server and comes with many other features to make developing your applications easier. They have pretty good, easy to follow documentation. There is a good "getting started" guide if you want to give them a try.
Spring Boot - Spring Boot is a bootstrapping framework that makes getting up and running with applications much easier. There are auto configurations made for you but give you options to change them. You can use Spring MVC or Jersey as the REST framework when you work with Spring Boot. There is also an Initializer, which is similar to the Maven Archetypes, but is interactive and allows you to add what you want to your applications.
So I just accepted the fact that java is an utter mess and pulled these dependencies in:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.4.2</version>
</dependency>
So i can launch everything like so:
public static void main(String[] args) throws Exception {
SomeDependency dependency = new SomeDependency();
Users usersEndpoint = new Users(dependency);
JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
serverFactory.setResourceClasses(usersEndpoint.getClass());
serverFactory.setResourceProvider(usersEndpoint.getClass(), new SingletonResourceProvider(usersEndpoint));
serverFactory.setAddress("http://localhost:8080/");
serverFactory.create().start();
}
I have more endpoints, of course, so I put everything in a for loop.
As to why I'm answering from a guest account, the account I used to ask this question was created using a disposable email address, and I can no longer access it.
Hope this helps anyone in the future!

Spring Webflux returns 404 ( Not Foud )

I have to save some values in a reactive way using spring Webflux. But when I send the request then 404 status is returned as a response.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
EmpController class
#RestController
#RequestMapping("/emp")
public class EmpController {
private EmployeeRepository empRepo;
#Autowired
public EmpController(EmployeeRepository empRepo)
{
this.empRepo=empRepo;
}
#PostMapping("/save")
#Consumes({MediaType.APPLICATION_JSON})
public void saveEmp(#RequestBody Mono<Employee> emp)
{
emp.subscribe(e-> {
e.setDate(new Date());
empRepo.saveEmp(e);
});
}
}
When I send the request via PostMan then 404(not found) is returned.
JAX-RS is a specification within Java EE of how to code REST api's. Several libraries have then implemented said specification, Like Jersey or restEasy. WHen building a Java EE application, you needed one of these libraries to be able to build a rest api.
Spring built their own way of building rest apis spring-web for non reactive applications, and spring-webflux for reactive applications.
Jersey and restEasy (to my knowledge) only works if you are building a non-reactive application.
In order to make your code work you need to remove:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
Jersey is a Java EE implementation of JAX-RS. It is used in Java EE to build Java EE styled rest apis. You are building a reactive application, using Spring Webflux which has its own way of building REST api's.
Spring is not a Java EE application. When you added that dependency, spring assumed that you wanted to build a Spring Application but not use the Spring built in REST api functions and annotations etc, so it didn't register your code, that you have written with Springs way of building rest apis.
It assumed you were going to write a REST api the "jersey way" and if you are using jersey you need to register your api classes manually. And (to my knowledge) Jersey only works with non-webflux applications.
This is all mainly basic knowledge, and if you dont understand why i suggest you read up and build a regular spring boot application, before trying out webflux.
I suggest you read the following parts:
Reactive programming, Reactor getting started
Baeldung Webflux
Building a reactive Webflux Application
Spring boot Webflux
It is Strange but when I removed jersey dependency and it Worked. Still not sure about the reason behind it.
raised pull request you the merge the same to take the changes I have done
https://github.com/Benzeman97/reactive-async-app/pull/1
You need to remove below Jersey dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
The reason behind is that the spring-boot-starter-jersey is a starter for building Restful web applications using JAX-RS and Jersey. Since you have used it in your project the spring does not use in built spring functions for rest api's like #GetMapping, #PostMapping.
If you want to use jersey to create the rest api then use #GET annotation for Get api and the #Produces to defined the mapping as below.
Eg.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.stereotype.Service;
#Service
#Path("/hello")
public class HelloService {
#GET
#Produces("text/plain")
public String hello() {
return "Hello from Spring";
}
}
Also you have to register this class in JerseyConfig.
import com.zetcode.endpoint.HelloService;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
#Configuration
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(HelloService.class);
}
}
And if you want to go ahead with the spring build in functions and use reactive just remove the jersey dependency and use webflux dependency to create your rest api's.
I had the same problem.
The solution:
go to application.properties,
remove server.servlet.context-path
and add spring.webflux.base-path

Use Java Websocket API in Spring Boot application

i want to use the java websocket API in a Spring Boot application.
I created the following class as described here:
https://www.baeldung.com/java-websockets
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#ServerEndpoint(value = "/test")
public class FrontendEndpoint {
#OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText("Test");
}
#OnMessage
public void onMessage(Session session, String message) throws IOException {
}
#OnClose
public void onClose(Session session) throws IOException {
}
#OnError
public void onError(Session session, Throwable throwable) {
}
}
I try to connect to that websocket but nothing happens. I saw a lot of articles in the internet but nothing helped me. I dont know how to get it to work.
When i try to connect to the websocket nothing happend.
Spring Boot version: 2.0.3
Websocket-API version: 1.1
I also don't see an open port for the websocket.
Thanks
BR
I once created a sample application with Spring Boot and Websocket API
https://github.com/simasch/spring-boot-websocket
but the problem is that the ServerEndpoint is not managed by Spring but by the Websocket implementation. So this is maybe not the way you should use websockets with Spring Boot.
I would recommend to have a look how Spring think that Websockets should be used:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#websocket
It's a bit late, but in case someone will come here for a solution.
It is not covered in Spring documentation how to use Java WebSocket API (JSR-356) in Spring and I didn't manage to find any tutorial describing how to achieve it despite I've spent several hours googling it.
In order to use Java WebSocket API with Spring you should use class org.springframework.web.socket.server.standard.SpringConfigurator:
https://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/web/socket/server/standard/SpringConfigurator.html
from
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>...</version>
</dependency>
Just add it to your
#ServerEndpoint(... configurator = SpringConfigurator.class)
and it is done. Your annotated class becomes a usual Spring-managed component legal for #Autowired injection and so on.
Hope it helps someone :)
UPD.
It should be mentioned, that JSR 356 WebSocket initialization through the SpringConfigurator is only supported in .war projects, that are to be deployed as usual artifacts in servlet container.
It will not work as expected when project is packaged in executable Spring Boot .jar or Spring Boot executable .war and when it is deployed it standalone mode via java -jar {app}
I didn't manage to find a way to initialize JSR 356 WebSocket with #Autowired Spring components in it in Spring Boot environment in executable archive.
It is possible to deploy JSR 356 WebSocket via ServerEndpointExporter.setAnnotatedEndpointClasses(...), but every class provided must have a no-arg constructor otherwise exception will be thrown. #Autowired field will not be processed by Spring in this case.
If you want to use java websocket API in a Spring Boot application you have to add this to spring configuration
#Configuration
public class WebSocketConfig {
#Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
Here is a full article.

Spring boot - Rest Call client without embedded tomcat

I have been trying to figure out an issue with spring boot and as i am new to spring I thought of getting some help here.
I have a spring boot based java application which runs as a daemon and makes some GET request to a remote server. (Acts only as a client).
But my spring boot application internally starts an embedded tomcat container.
My understanding is that if the java app acts as a server, it would need tomcat. But my application being only a consumer of remote machine's GET APIs, why would it need an embedded tomcat ?
In my pom file I have specified spring-boot-starter-web,
on assumption that it is needed for even making GET calls.
But after doing some research on disabling embedded tomcat, I found a solution.
To make following changes,
#SpringBootApplication(exclude = {EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class})
&
in application.yml
spring:
main:
web-environment: false
With the application.yml changes, my jar is not even getting started, aborts directly, without even logging anything in logback logs.
Now, if i remove the application.yml change, my jar starts (only with first change in #SpringBootApplication anno.) but goes into some exception.
[main] o.s.boot.SpringApplication : Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
My Doubts here are,
1) Is tomcat, be it standalone or embedded, really needed for a application which just makes GET API calls to remote machine ?
2) How do i overcome this exception and safely remove the embedded tomcat and still perform the GET API calls ?
You seem to be on completely the wrong track here, starting from a web application template and then trying to turn off the web application aspect.
Far better to start from a regular commandline client template and go from there, as detailed in the relevant Spring Guide.
Basically the application reduces to
#SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String args[]) {
SpringApplication.run(Application.class);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
Quote quote = restTemplate.getForObject(
"http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
};
}
}
And the pom to
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
I had this problem. All I wanted was to have a Client making REST requests. Unfortunately I had a dependency which was embedding Jetty, and Jetty was always started.
In order to disable Jetty all I needed to do was to add in applications.properties the following entry:
spring.main.web-application-type=none
That fixed it.
Here is the most simple solution for me, make spring boot application just a restful api consumer.
Replace the dependence
implementation("org.springframework.boot:spring-boot-starter-web")
with
implementation("org.springframework.boot:spring-boot-starter-json")
RestTemplate and jackson are available in the project without embedded tomcat.
Answering your questions:
1) embedded by defaut - not needed for clients HTTP requests;
2) You can use CommandLineRunner for spring boot applications without any web:
#SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
#Override
public void run(String... args) {
// TODO: start you thread here to execute client HTTP REST requests (or any other job you need)
}
}
This will disable web completelly - no issues with manual miss-configuration.
Here is some docs:
http://www.baeldung.com/spring-boot-console-app
You also need replase spring-boot-starter-web dependency with spring-boot-starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
From your question, i assume you want your application to keep running in background and it makes some get calls in it's life cycle. If that's the case, then
answering your first question, yes, you need an embedded tomcat or
jetty or need to deploy your application to an external application
server.
Second, to get rid of the exception your facing, don't exclude
EmbeddedServletContainerAutoConfiguration and
WebMvcAutoConfiguration class as it's needed for default embedded
tomcat auto configuration.

In-process SOAP service server for Java

OK, I am developing a program which will be deployed to lots of machines (Windows, Linux, AIX, z/Linux, openVMS, etc.). I want that application to contain a SOAP web service, but I don't want to bundle tomcat or run a separate service for the services (I want them in the same process as the rest of the application).
Basically what I'm looking for is something where I can define a class (say WebServices). I'm OK with writing WSDL or any other kind of service description as well. The I want something like this:
SOAPServer server = makeMeASoapServer();
//do config on the server
server.add(new WebService(...));
server.listen(port);
Obviously the names and parameters will be different.
I've been looking at Axis, and it seems like it provides this, but I don't know what classes I need to use. Am I crazy in wanting this kind of behavior? I can't believe more people aren't looking for this, I do this all the time with embedded web services within .NET clients.
Seems jdk 6.0 already comes with a jax-ws implementation, and a little server you can embed.
I havn't figured out all the pieces but here's a start:
mkdir -p helloservice/endpoint/
helloservice/endpoint/Hello.java :
package helloservice.endpoint;
import javax.jws.WebService;
#WebService()
public class Hello {
private String message = new String("Hello, ");
public void Hello() {}
public String sayHello(String name) {
return message + name + ".";
}
}
helloservice/endpoint/Server.java:
package helloservice.endpoint;
import javax.xml.ws.Endpoint;
public class Server {
protected Server() throws Exception {
System.out.println("Starting Server");
Object implementor = new Hello();
String address = "http://localhost:9000/SoapContext/SoapPort";
Endpoint.publish(address, implementor);
}
public static void main(String args[]) throws Exception {
new Server();
System.out.println("Server ready...");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}
Build the thing:
mkdir build
javac -d build helloservice/endpoint/*java
$JAVA_HOME/wsgen -d build -s build -classpath . helloservice.endpoint.Hello
Run the thing:
java -cp build helloservice.endpoint.Server
Somethings running on http://localhost:9000/SoapContext/SoapPort now.
You can get the wsdl on http://localhost:9000/SoapContext/SoapPort?WSDL
Havn't gotten around to making a client yet..
In addition to nos's great answer, I found a class in Apache axis called SimpleHTTPServer which I'm pretty sure does the same thing but only requires Java 1.5 for those of you stuck with 1.5
I'm not going to explore it since I'm going to use the other solution, so I haven't actually verified it does what I think it does, but I'm pretty sure it does.
Most(/all?) Java SOAP server implementations provide a Servlet (the javax.xml.ws.Endpoint approach in another answer does look a bit simpler though...). Some SOAP implementations you could consider are: Apache CXF: cxf.apache.org, Apache Axis2: ws.apache.org/axis2/ or Spring Web Servies: static.springsource.org/spring-ws/site/ .
The most popular embedded Java web server seems to be Jetty, you can configure it either programatically (using plain Java or Spring beans) or using a custom XML format.
To address the main question directly, another approach would be to go with Jetty's embedded server. See this link for details. The links from the aforelinked page help you understand both the simple web server (i.e., one that serves up static pages; though I am fully aware "simple" is a horribly vague term wrt web servers) and the web server that helps you deploy web services.

Categories

Resources