I`m going right on this tutorial https://spring.io/guides/gs/uploading-files/
and implemented a multipart file upload controller.
However, stuck on getting this error:
type Exception report
message Request processing failed; nested exception is java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
description The server encountered an internal error that prevented it from fulfilling this request.
Here is my code for controller, just right from official tutorial:
package com.springapp.mvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
#Controller
public class FileUploadController {
#RequestMapping(value="/api/items/upload_image", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file){
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + "!";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
}
And just for additional info, this is how i send request from front-end on angularjs. Request senging successfully:
Upload.upload({
url: '/api/items/upload_image',
file: $file,
name: $file.name,
progress: function(e){}
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
What i the problem can be?
All needed dependencies included.
This was a solution:
include this dependencies in pom.xml
<!-- Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
Add this bean in configuration:
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- setting maximum upload size -->
<property name="maxUploadSize" value="100000" />
</bean>
Related
I'm new to RESTful services and Jersey. I'm trying to create a ws that respond to POST call with enctype mutipart/form-data.
First of all I have my application Class
import com.ibm.sampleapp.rest.ConversationWS;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
#ApplicationPath("/api")
public class WinkApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
enter code here
// Returns the list of classes which are to be added as REST endpoints
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MultiPartFeature.class);
classes.add(FormDataContentDisposition.class);
classes.add(RESTws.class);
return classes;
}
and then I have my rest service class
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
#Path("")
public class RESTws extends ResourceConfig {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileMetaData) throws Exception {
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(MultiPartFeature.class);
resourceConfig.register(FormDataContentDisposition.class);
String filename = fileMetaData.getFileName();
String uploadedFileLocation = "C:\\$User\\Doc\\" + filename;
try {
saveFile(uploadedInputStream, uploadedFileLocation);
}
catch(Exception e){
return Response.status(400).entity(e.getCause()).build();
}
String output = "File uploaded to: " + uploadedFileLocation;
System.out.println("File uploaded..");
return Response.status(200).entity(output).build();
}
// save uploaded file to a defined location on the server
private void saveFile(InputStream uploadedInputStream,
String serverLocation) {
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
outpuStream.write(bytes, 0, read);
}
outpuStream.flush();
outpuStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Finally i have the index.html in which i upload the file
<!DOCTYPE html>
<html>
<head>
<title>Java Web Starter Application</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>RESTful Web Service - File Upload Example</h1>
<form action="http://localhost:9080/java-sample-backend/api/upload" method="post" enctype="multipart/form-data">
<p>
Select a file to Upload to server: <input type="file" name="file" size="60" />
</p>
<input type="submit" value="Upload File" />
</form>
</body>
</html>
My dependencies are:
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.22.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.22.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.22.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.21</version>
</dependency>
When I try to upload a file trough my html i get the following error:
[ERROR ] No message body reader has been found for class org.glassfish.jersey.media.multipart.FormDataContentDisposition, ContentType: multipart/form-data;boundary=---------------------------7e21f97403c2
Googling around the issue I understand that my problem is that I do not have my service registered, but I can not understand how I can achieve it.
Is there a way to do it programmatically and not via web.xml file?
-
Thank you very much for your help.
You need a class like MyRestApplication extends ResourceConfig that is annotated with #ApplicationPath("/PATH"). In the constructor of this class you call register( MultiPartFeature.class ); and register your service classes using registerClasses( MyService.class );.
The class MyService does not extend any other class but must be annotated by #Path("/SERVICEPATH"). This class then contains method uploadFile.
You don't need a web.xml.
This is a follow up to the solution which was provided to me on this previous post:
How to Properly Close Raw RestClient When Using Elastic Search 5.5.0 for Optimal Performance?
This same exact error message came back!
2017-09-29 18:50:22.497 ERROR 11099 --- [8080-Acceptor-0] org.apache.tomcat.util.net.NioEndpoint : Socket accept failed
java.io.IOException: Too many open files
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) ~[na:1.8.0_141]
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422) ~[na:1.8.0_141]
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250) ~[na:1.8.0_141]
at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:453) ~[tomcat-embed-core-8.5.15.jar!/:8.5.15]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_141]
2017-09-29 18:50:23.885 INFO 11099 --- [Thread-3] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#5387f9e0: startup date [Wed Sep 27 03:14:35 UTC 2017]; root of context hierarchy
2017-09-29 18:50:23.890 INFO 11099 --- [Thread-3] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2017-09-29 18:50:23.891 WARN 11099 --- [Thread-3] o.s.c.support.DefaultLifecycleProcessor : Failed to stop bean 'documentationPluginsBootstrapper'
... 7 common frames omitted
2017-09-29 18:50:53.891 WARN 11099 --- [Thread-3] o.s.c.support.DefaultLifecycleProcessor : Failed to shut down 1 bean with phase value 2147483647 within timeout of 30000: [documentationPluginsBootstrapper]
2017-09-29 18:50:53.891 INFO 11099 --- [Thread-3] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2017-09-29 18:50:53.894 INFO 11099 --- [Thread-3] com.app.controller.SearchController : Closing the ES REST client
I tried using the solution from the previous post.
ElasticsearchConfig:
#Configuration
public class ElasticsearchConfig {
#Value("${elasticsearch.host}")
private String host;
#Value("${elasticsearch.port}")
private int port;
#Bean
public RestClient restClient() {
return RestClient.builder(new HttpHost(host, port))
.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
#Override
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
return requestConfigBuilder.setConnectTimeout(5000).setSocketTimeout(60000);
}
}).setMaxRetryTimeoutMillis(60000).build();
}
SearchController:
#RestController
#RequestMapping("/api/v1")
public class SearchController {
#Autowired
private RestClient restClient;
#RequestMapping(value = "/search", method = RequestMethod.GET, produces="application/json" )
public ResponseEntity<Object> getSearchQueryResults(#RequestParam(value = "criteria") String criteria) throws IOException {
// Setup HTTP Headers
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
// Setup query and send and return ResponseEntity...
Response response = this.restClient.performRequest(...);
}
#PreDestroy
public void cleanup() {
try {
logger.info("Closing the ES REST client");
this.restClient.close();
}
catch (IOException ioe) {
logger.error("Problem occurred when closing the ES REST client", ioe);
}
}
}
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.5.0</version>
</dependency>
<!-- Apache Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<!-- Log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
This makes me think that the RestClient was never explicitly closing the connection, in the first place...
And this is surprising since my Elasticsearch Spring Boot based Microservice is load balanced on two different AWS EC-2 Servers.
That exception occurreded like 2000 times reported by the log file and only in the end did the preDestroy() close the client. See the INFO from the #PreDestroy() cleanup method being logged at the end of the StackTrace.
Do I need to explicitly put a finally clause inside the SearchController and close the RestClient connection explicitly?
It's really critical that this IOException doesn't happen again because this Search Microservice is dependent on a lot of different mobile clients (iOS & Android).
Need this to be fault tolerant and scalable... Or, at the very least, not to break.
The only reason this is in the bottom of the log file:
2017-09-29 18:50:53.894 INFO 11099 --- [Thread-3] com.app.controller.SearchController : Closing the ES REST client
Is because I did this:
kill -3 jvm_pid
Should I keep the #PreDestory cleanup() method but change the contents of my SearchController.getSearchResults() method to reflect something like this:
#RequestMapping(value = "/search", method = RequestMethod.GET, produces="application/json" )
public ResponseEntity<Object> getSearchQueryResults(#RequestParam(value = "criteria") String criteria) throws IOException {
// Setup HTTP Headers
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
// Setup query and send and return ResponseEntity...
Response response = null;
try {
// Submit Query and Obtain Response
response = this.restClient.performRequest("POST", endPoint, Collections.singletonMap("pretty", "true"), entity);
}
catch(IOException ioe) {
logger.error("Exception when performing POST request " + ioe);
}
finally {
this.restClient.close();
}
// return response as EsResponse();
}
This way the RestClient connection is always closing...
Would appreciate if someone can help me with this.
From my point of view, there are few thing that you are doing wrong but I will go directly to the solution.
I'm not going to write the full solution (in fact, I didn't execute or test anything), but the important is to understand it. Also, it is better if you move all related with data access to another layer. Anyway, this is only an example so the design is not perfect.
Step 1: Import the right library.
Practically the same as your example.
I updated the example to use the last client library recommended in version 5.6.2
<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.acervera</groupId>
<artifactId>elastic-example</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>elastic-example</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<es.version>5.6.2</es.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${es.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${es.version}</version>
</dependency>
<!-- Log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
Step 2: Create and shutdown the client in the bean factory.
In the bean factory, create and destroy it. You can reuse the same client.
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
#Configuration
public class ElasticsearchConfig {
// Here all init stuff with #Value(....)
RestClient lowLevelRestClient;
RestHighLevelClient client;
#PostConstruct
public void init() {
lowLevelRestClient = RestClient.builder(new HttpHost("host", 9200, "http")).build();
client = new RestHighLevelClient(lowLevelRestClient);
}
#PreDestroy
public void destroy() throws IOException {
lowLevelRestClient.close();
}
#Bean
public RestHighLevelClient getClient() {
return client;
}
}
Step 3: Execute the query using the Java Transport Client.
Use the Java Transport Client to execute the query.
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
#RestController
#RequestMapping("/api/v1")
public class SearchController {
#Autowired
private RestHighLevelClient client;
#RequestMapping(value = "/search", method = RequestMethod.GET, produces="application/json" )
public ResponseEntity<Tweet> getSearchQueryResults(#RequestParam(value = "criteria") String criteria) throws IOException {
// This is only one example. Of course, this logic make non sense and you are going to put it in a DAO
// layer with more logical stuff
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
SearchResponse searchResponse = client.search(searchRequest);
if(searchResponse.getHits().totalHits > 0) {
SearchHit searchHit = searchResponse.getHits().iterator().next();
// Deserialize to Java. The best option is to use response.getSource() and Jackson
// This is other option.
Tweet tweet = new Tweet();
tweet.setId(searchHit.getField("id").getValue().toString());
tweet.setTittle(searchHit.getField("tittle").getValue().toString());
return ResponseEntity.ok(tweet);
} else {
return ResponseEntity.notFound().build();
}
}
}
Also, use a bean to build the response.
public class Tweet {
private String id;
private String tittle;
public String getTittle() {
return tittle;
}
public void setTittle(String tittle) {
this.tittle = tittle;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
// Here rest of bean stuff (equal, hash, etc) or Lombok
}
Step: 4
Enjoy Elasticsearch!
Notes: Java REST Client [5.6] » Java High Level REST Client
PS. It is necessary to refactor the example. It is only to understand the way.
Are you sure that you don't initiate a new (thread pool) connection to the elasticsearch server on every HTTP request? I.e., in line
Response response = this.restClient.performRequest(...);
Double-check the logs on the elasticsearch server after a single HTTP request. You should try implementing a Singleton pattern without the #Autowired annotation and see if the problem persists.
From your stacktrace, it appears that embedded tomcat(your application container) is not longer able to accept new connection due to too many open files error. From your code, elasticsearch rest client does not seems problematic.
Since you are re-using the single instance of RestClient while servicing your search request, there may not be more more than 30 (org.elasticsearch.client.RestClientBuilder.DEFAULT_MAX_CONN_TOTAL) open connections with ES cluster. So it is unlikely that RestClient it is causing the issue.
Other potential root cause may be your service's consumer are keeping connection open for longer time with your (tomcat) server or they are not closing connection properly.
Do I need to explicitly put a finally clause inside the
SearchController and close the RestClient connection explicitly?
No. You shouldn't. Rest client should be closed while bringing down your service(in a #PreDestroy method as you are already doing correctly).
I am trying to configure web sockets with spring using a Wildfly 10 server. As per this tutorial, I have the following files:
This is the web socket class:
package com.myapp.spring.web.controller;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
import org.springframework.web.socket.server.standard.SpringConfigurator;
#ServerEndpoint(value="/serverendpoint", configurator = SpringConfigurator.class)
/**
* This class creates web sockets, opens, and maintains connection with the client
*/
public class serverendpoint {
#OnOpen
public void handleOpen () {
System.out.println("JAVA: Client is now connected...");
}
#OnMessage
public String handleMessage (String message) {
if (message.equals("ping"))
return "pong";
else if (message.equals("close")) {
handleClose();
return null;
}
System.out.println("JAVA: Received from client: "+ message);
if (message.contains("//")) {
MyClass mc = new MyClass(message);
return mc.someMethod();
} else {
System.out.println("Message From Web Socket Not Understood");
return null;
}
}
#OnClose
public void handleClose() {
System.out.println("JAVA: Client is now disconnected...");
}
#OnError
public void handleError (Throwable t) {
t.printStackTrace();
}
}
This is the web socket config file:
package com.myapp.spring.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import com.myapp.spring.web.controller.serverendpoint;
#Configuration
public class EndpointConfig {
#Bean
public serverendpoint serverendpoint() {
return new serverendpoint();
}
#Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
}
}
This is my pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
According to the tutorial, this is all I have to do. But I get the following errors:
Failed to start service jboss.undertow.deployment.default-server.default-host./ROOT: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./ROOT: java.lang.RuntimeException: java.lang.ClassCastException: org.apache.tomcat.websocket.server.WsServerContainer cannot be cast to io.undertow.websockets.jsr.ServerWebSocketContainer
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: java.lang.ClassCastException: org.apache.tomcat.websocket.server.WsServerContainer cannot be cast to io.undertow.websockets.jsr.ServerWebSocketContainer
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:231)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
... 6 more
Caused by: java.lang.ClassCastException: org.apache.tomcat.websocket.server.WsServerContainer cannot be cast to io.undertow.websockets.jsr.ServerWebSocketContainer
at io.undertow.websockets.jsr.Bootstrap$WebSocketListener.contextInitialized(Bootstrap.java:104)
at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:198)
... 8 more
What is the fix to this problem? In addition, are there any other config files I need to add in order for my web socket to be mapped correctly at the endpoint /serverendpoint as I did in my serverendpoint() class (I am asking this because I am a bit unsure if I only need one config file or not. It doesn't seem right. I looked around and others have included other files with, for instance, the #EnableWebSocket, but the tutorial says that I only need these two files.)?
Thank you so much!
Please go through https://github.com/spring-projects/spring-boot/issues/6166 and see if this solves your issue.
There is a similar issue reported in SO at Spring Boot Websockets in Wildfly. Hope this helps.
I get the following exception when I execute the REST Client :
InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:8080/com.dcr.jersey.first/webapi/todo, status=406, reason=Not Acceptable}}
Exception in thread "main" javax.ws.rs.NotAcceptableException: HTTP 406 Not Acceptable
On web browser( when tomcat is running), the URL : http://localhost:8080/com.dcr.jersey.first/webapi/todo gives output
todo>
<description>This is my first todo - Description</description>
<summary>This is my first todo - Summary</summary>
</todo>
But running the client code throws the exception, what is the mapping that's missing here?, appreciate your guidance( included all code samples)
Here is the web.xml :
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<!-- <param-value>com.dcr.jersey</param-value> -->
<!-- <param-value>com.dcr.jersey.first</param-value> -->
<param-value>com.dcr.jersey.jaxb.model</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>
Here is the TodoResourceCliient executed:
package com.dcr.jersey.client;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.client.ClientConfig;
public class TodoResourceCliient {
public static void main(String[] args) {
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target(getBaseURI());
System.out.println(target.path("webapi").path("todo").request()
.accept(MediaType.TEXT_PLAIN).get(Response.class)
.toString());
System.out.println(target.path("webapi").path("todo").request()
.accept(MediaType.TEXT_HTML).get(String.class));
System.out.println(target.path("webapi").path("todo").request()
.accept(MediaType.TEXT_XML).get(String.class));
System.out.println(target.path("webapi").path("todo").request()
.accept(MediaType.TEXT_PLAIN).get(String.class));
System.out.println(target.path("webapi").path("todo").request()
.accept(MediaType.APPLICATION_JSON).get(String.class));
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/com.dcr.jersey.first").build();
}
}
TodoResource.java:
package com.dcr.jersey.jaxb.model;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/todo")
public class TodoResource {
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Todo getXML() {
Todo todo = new Todo();
todo.setSummary("This is my first todo - Summary\n");
todo.setDescription("This is my first todo - Description\n");
return todo;
}
// This can be used to test the integration with the browser
#GET
#Produces({ MediaType.TEXT_XML,MediaType.TEXT_PLAIN,MediaType.TEXT_HTML})
public Todo getHTML() {
Todo todo = new Todo();
todo.setSummary("This is my first todo - Summary\n");
todo.setDescription("This is my first todo - Description\n");
return todo;
}
}
Todo.java:
package com.dcr.jersey.jaxb.model;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Todo {
private String summary;
private String description;
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Stacktrace from Console :
InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:8080/com.dcr.jersey.first/webapi/todo, status=500, reason=Internal Server Error}}
Exception in thread "main" javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1002)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:799)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:91)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:687)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:683)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:411)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:307)
at com.dcr.jersey.client.TodoResourceCliient.main(TodoResourceCliient.java:27)
Dependencies included from pom.xml: am I missing any dependencies ?
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<!-- JSON support -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
</dependencies>
See Http Status Codes
406 Not Acceptable
The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.
The .accept(mediatype) is what set the Accept header for the request. You currently have five requests, each accepting a different type
MediaType.TEXT_PLAIN,MediaType.TEXT_HTML, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON
This is Content-Negotiation at work. The server side configuration of this is with the use of the #Produces (which goes in hand with the Accept header) and #Consumes(which goes in hand with the Content-Type header).
That being said, look at all your #Produces annotations. You currently only support the producing of media types
MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON
The missing ones are in bold above. Remove those, and given all else is correct, this should work for you.
Check your content type!
Setting to .accept(MediaType.TEXT_PLAIN) worked for me.
As correctly stated by peeskillet, your client calls with accept(MediaType.TEXT_PLAIN) and accept(MediaType.TEXT_HTML) will cause issues since your TodoResource methods do not specify these media types in the #Produces annotation.
Either
change your TodoResource class to support these media types
change your client code to remove the calls corresponding to these media types
I am trying to upload an image to a servlet, but every once and a while during automated testing, it silently fails.
Do you guys know what would cause this?
Here is the code on the server:
#ResponseBody
#RequestMapping(method = RequestMethod.POST)
public String upload(HttpServletRequest request) throws Exception {
BufferedImage image = null;
#SuppressWarnings("unchecked")
List<FileItem> items = new ServletFileUpload(
new DiskFileItemFactory()).parseRequest(request);
Logger.log(LogLevel.INFO, "Upload contains " + items.size()
+ " items.");
int i = 0;
for (FileItem item : items) {
Logger.log(LogLevel.INFO, "\tItem " + (i++) + ". Name:\t"
+ item.getName() + ", Type:\t" + item.getContentType());
// File is of type "file"
if (!item.isFormField()) {
InputStream inputStream = null;
try {
inputStream = item.getInputStream();
if (inputStream.available() == 0) {
Logger.log(LogLevel.WARN,
"Item shows file type, but no bytes are available");
}
image = ImageIO.read(inputStream);
if (image != null) {
break;
}
} catch (Exception e) {
Logger.log(LogLevel.ERROR,
"There was an error reading the image. "
+ ExceptionUtils.getFullStackTrace(e));
throw new Exception("image provided is not a valid image");
} finally {
if (inputStream != null) {
IOUtils.closeQuietly(inputStream);
}
}
}
}
if (image == null) {
Logger.log(LogLevel.ERROR, "Image was supposedly read correctly, but was null afterwards");
throw new Exception("Image provided could not be read");
}
//do stuff with image
...
}
Here is the test:
public void testImageUpload throws Exception {
HttpPost httppost = new HttpPost("path/to/endpoint");
File file=new File(imgLoc);
FileBody bin = new FileBody(file);
StringBody comment = new StringBody("Filename: " + file);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("upload-file", bin);
reqEntity.addPart("comment", comment);
httppost.setHeader("Accept", "application/json");
httppost.setHeader("Connection","Keep-Alive");
httppost.setEntity(reqEntity);
HttpResponse response =testClient.getClient().execute(httppost);
imgResponse=response.getStatusLine().toString();
System.out.println(imgResponse);
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line;
while ((line = reader.readLine()) != null){
output = output + " " +line;}
System.out.println("Image Response: "+output);
}
Here is the output from the server when it fails:
2013/10/02 05-53-32,287::LOG:INFO[com.example#upload:L130 -- Upload contains 2 items.]
2013/10/02 05-53-32,288::LOG:INFO[com.example#upload:L133 -- Item 0. Name: Dog.jpg, Type: application/octet-stream]
2013/10/02 05-53-32,288::LOG:WARN[com.example#upload:L140 -- Item shows file type, but no bytes are available]
2013/10/02 05-53-32,289::LOG:INFO[com.example#upload:L133 -- Item 1. Name: null, Type: text/plain; charset=ISO-8859-1]
2013/10/02 05-53-32,290::LOG:ERROR[com.example#upload:L159 -- Image was supposedly read correctly, but was null afterwards]
We catch the exception from the image upload and send back a response code of 422 back to the client, so on the test, we get imgResponse==422 which is a failure case.
Note: this only happens sometimes you run the test.
Here is step by step configuration for file uploading by using Apache Commons FileUpload:
1. Add dependency jars for the following component. Here is the maven dependencies:
pom.xml
<dependencies>
<!-- Spring 3 MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<!-- Apache Commons file upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- JSTL for c: tag -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
If you are not using maven then download respective jar from the maven repository online.
2. Create a FileUploadForm model
FileUploadForm.java
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class FileUploadForm {
private List<MultipartFile> files;
//Getter and setter methods
}
3. Add resolver to MVC config file
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
4. Write FileUploadController
FileUploadController.java
#Controller
public class FileUploadController {
#RequestMapping(value = "/show", method = RequestMethod.GET)
public String displayForm() {
return "file_upload_form";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(
#ModelAttribute("uploadForm") FileUploadForm uploadForm,
Model map) {
List<MultipartFile> files = uploadForm.getFiles();
List<String> fileNames = new ArrayList<String>();
if(null != files && files.size() > 0) {
for (MultipartFile multipartFile : files) {
String fileName = multipartFile.getOriginalFilename();
fileNames.add(fileName);
//Handle file content - multipartFile.getInputStream()
}
}
map.addAttribute("files", fileNames);
return "file_upload_success";
}
}
5. Write jsp views
file_upload_form.jsp
<html>
<head>
<title>Spring MVC Multiple File Upload</title>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
//add more file components if Add is clicked
$('#addFile').click(function() {
var fileIndex = $('#fileTable tr').children().length - 1;
$('#fileTable').append(
'<tr><td>'+
' <input type="file" name="files['+ fileIndex +']" />'+
'</td></tr>');
});
});
</script>
</head>
<body>
<h1>Spring Multiple File Upload example</h1>
<form method="post" action="save.html"
**enctype="multipart/form-data"**>
<p>Select files to upload. Press Add button to add more file inputs.</p>
<input id="addFile" type="button" value="Add File" />
<table id="fileTable">
<tr>
<td><input name="files[0]" type="file" /></td>
</tr>
<tr>
<td><input name="files[1]" type="file" /></td>
</tr>
</table>
<br/><input type="submit" value="Upload" />
</form>
</body>
</html>
Reference: http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-multipart
It seems your content type is application/octet-stream. Please add the below Header in your request and give a try
("Content-Type", "multipart/form-data");
You are using InputStream#available. As the documentation states this is the number of bytes that can be read from the stream without blocking. Now, how many bytes are available from the TCP input stream depends on the size of the the packets and how your request is sliced amongst them (and a lot more other factors).
If your intention is to always read the stream in full, forget the available() method, just read it out until the end of stream and you should be fine.
I've come across this before under two conditions. Once was when I ran low on disk space and the other was when I was doing a bit of load test.
If you take a look at the How it works page, you can make the tool dump items to disk or keep them in memory. Under one case I filled up the drive during testing and the other I was keeping items in memory but the load blew my memory limit.
How do you have it set up? How big is the image you are using to test? How many times do yo upload it during your tests? With this info, I should be able to help a bit more.
This code is used on my site currently, works like a charm:
package com.example;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
#Controller
#RequestMapping("/api/media")
public class ImageRestService {
private static final Logger LOG = LoggerFactory.getLogger(ImageRestService.class);
#RequestMapping(value = "/uploadtemp", method = RequestMethod.POST)
public String upload(#RequestParam(value = "image") MultipartFile image) {
try {
BufferedImage bufferedImage = ImageIO.read(image.getInputStream());
// process image here
} catch (IOException e) {
LOG.error("failed to process image", e);
return "failure/view/name";
}
return "success/view/name";
}
}
Maybe the order of the items list is not fixed (timing dependent?). Your code
if (image != null) {
break;
}
quits the loop instead of trying the next parts. In the comments you state we iterate through the files until we can parse one, which should read
if (image != null) {
continue;
}
then.