CASE
I am trying to fetch User data to Servlet filter using REST service.
POM.xml
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
CODE
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Client client = ClientBuilder.newClient(new ClientConfig());
String entity = client.target("http://localhost:8080/insame/webresources/com.insame.entity.users")
.path("count")
.request(MediaType.TEXT_PLAIN)
.get(String.class);
System.out.println("entity-------->" +entity);
REST:
#GET
#Path("count")
#Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
PROBLEM
javax.ws.rs.ProcessingException: java.net.SocketException: Unexpected end of file from server
at org.glassfish.jersey.client.HttpUrlConnector.apply(HttpUrlConnector.java:202)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:215)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:650)
WARNING: StandardWrapperValve[com.insame.service.ApplicationConfig]: Servlet.service() for servlet com.insame.service.ApplicationConfig threw exception
javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:904)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:749)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:88)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:650)
QUESTION
0) What is wrong in my code?
1) What is the wisest way to fetch data from servlet filter using
REST + JPA?
2) If there is another way to do this, better I mean,
pls let me know?
3) Is the Jersey Client the only way
4) How can I
get EntityManager and call the rest service straight from filter
without Jersey Client?
Jersey documentation and examples:
http://jersey.java.net/documentation/latest/user-guide.html#d0e2481
Thanks,
Sami
0) 500 error code means there is some thing wrong on Server side. May be the action action threw some error even though REST got processed.
1) for simple REST, I have used Restlet and HttpClient. Even jerseyClient with JAXB to process response as POJOs. In my experience, simple HTTP is the best and simplest way to process REST response. You can easily write a wrapper on http code (java.net) to process request/response, create Dom around that
2) and 3) are answered above
Related
I'm using quarkus version 2.3.0.Final.
I have a rest endpoint in the Controller layer:
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Uni<Response> uploadFile(#MultipartForm FormData formData) {
return documentService.uploadFile(formData).onItem()
.transform(value -> Response.status(200)
.entity(value)
.build());
}
and in the service layer the code
public Uni<?> uploadFile(#NonNull FormData formData) throws Exception {
// Call to graphQl client using blocking process - the problem occurs here,
RevisionResponse revisionResponse = entityRepository.createRevision(formData);
// Do upload to s3 using s3 Async
return Uni.createFrom()
.future(
storageProviderFactory.getDefaultStorageProvider().upload(formData)))
.map(storageUploadResponse -> DocumentResponse.builder()
.id(revisionResponse.getId())
.entityMasterId(revisionResponse.getEntityMasterId())
.type(revisionResponse.getType())
.path(formData.getFilePath())
.description(formData.getDescription())
.build());
}
and here are the dependencies that I used:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-graphql-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jsonb</artifactId>
</dependency>
When I run this function, it's being blocked in entityRepository.createRevision(formData) (The console show the graphql request log but actually, the request even does not hit the target graphql endpoint)
However, if I add the annotation #Blocking in the controller layer, everything works as expected.
I also tried with Uni response for Uni<RevisionResponse> revisionResponse = entityRepository.createRevision(formData); but the same error happens.
Does anyone face these issues, did I config something wrong for the non-blocking processed?
Thank you.
For those who face with the same issue to me, I fix it by wrapping the blocking code with Uni:
Uni<RevisionResponse> revisionResponse = Uni.createForm().item(entityRepository.createRevision(formData));
Ref link: https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive#running-blocking-code-on-subscription
Because you are returning Uni from your method, RESTEasy Reactive is running the method on the event loop (see this for details).
However, it looks like the call to entityRepository.createRevision is blocking IO, which means that the event loop thread is being blocked - something which is not allowed to happen.
Using the #Blocking annotation means that the request is being serviced on a worker pool thread, on which you are allowed to block.
I'm noticing a weird issue with multipart request here.
Below is the Jersey2 implementation used in Spring Boot 2.4.2:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces({MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_JSON})
public void upload(#FormDataParam("params") MyPojo req,
#FormDataParam("file") FormDataBodyPart file, #Context HttpHeaders headers, #Suspended AsyncResponse ar)
{
...
}
and following the Spring Boot dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
I am able to successfully upload JSON and file (as multipart/form-data) using Postman but the same request from Java client throws below error:
Caused by: org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
This article on SO says we need to add a CommonsMultipartResolver but why as it works all good from Postman client??
Appreciate any hints or suggestions, thanks.
Updating Java Apache client code:
final Document document = getDocument(documentId);
final String requestParams = getRequestParams(document);
final String documentContentType = document.getContentType();
final URL endpoint = getServiceEndpoint();
final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().addTextBody(REQUEST_PARAMS_PARAMETER_NAME, requestParams, ContentType.APPLICATION_JSON);
if (isSendDocument() && documentFile != null) {
entityBuilder.addBinaryBody(DOCUMENT_CONTENT_PARAMETER_NAME, documentFile, ContentType.parse(documentContentType), document.getContentType());
}
final HttpEntity reqestEntity = entityBuilder.build();
connection = (HttpURLConnection)endpoint.openConnection();
connection.setAllowUserInteraction(false);
connection.setConnectTimeout(getConnectionTimeout());
connection.setReadTimeout(getReadTimeout());
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty(X_REQUESTED_WITH_HEADER_NAME, "XMLHttpRequest");
connection.addRequestProperty(X_REQUESTED_BY_HEADER_NAME, "XMLHttpRequest");
connection.addRequestProperty(ACCEPT_HEADER_NAME, ContentType.APPLICATION_JSON.getMimeType());
connection.addRequestProperty(CONTENT_TYPE_HEADER_NAME, reqestEntity.getContentType().getValue());
outStream = connection.getOutputStream();
reqestEntity.writeTo(outStream);
outStream.flush();
As we intend the multipart to be handled by the Jersey servlet, #PaulSamsotha suggestion to disable Spring Boot's multipart processing spring.servlet.multipart.enabled = false resolved the original issue posted in the question - "java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided".
Later, I was getting a Http 400 error only with Apache client and that was due to malformed JSON payload. Thanks for all the support.
I'm using Netflix' Hystrix libraries to act as a circuit breaker when connecting to remote services in a REST client I am building. I would like to setup the event streaming and dashboard monitoring via the libraries they provide. Looking at their example application here, it appears that I need to apply their servlet filters and servlet classes to my web application.
I'm using Spring Boot with Jersey 2 and wiring up my resources and filters in a JerseyConfig.java (no web.xml). I know that Jersey Filters are not the same as Servlet Filters and am struggling to integrate the two together.
So, how do you take a Java Servlet Filter and make it work as a Jersey Filter and how do you take a Java Servlet and make it work as a Jersey Resource?
My current strategy for the Servlets is to wrap them like so. One for each.
#Path("/hystrix.stream")
public class HystrixResource extends HystrixUtilizationSseServlet {
#Context
HttpServletRequest httpRequest;
#Context
HttpServletResponse httpResponse;
//This returns void because it is a text/stream output that must remain open,
//so the httpResponse is continually written to until the conenction is closed
#GET
public void doGet() throws ServletException, IOException {
doGet(httpRequest, httpResponse);
}
}
This might be working, but the data is basically empty for some reason. I am guessing that reason is because the Filters are not working.
data: {"type":"HystrixUtilization","commands":{},"threadpools":{}}
It is less clear to me how to wrap the Servlet Filters because they expect different inputs and outputs than a Jersey ContainerRequestFilter. The following implementation in my JerseyConfig seems to do nothing because the logs are not indicating that the filters are being registered and I cannot break on lines in these files in debug mode.
#Component
#ApplicationPath("/")
public class JerseyConfig extends ResourceConfig {
private static final Logger LOGGER = Logger.getLogger("JerseyConfig");
public JerseyConfig(){
//filter to provide a bridge between JAX-RS and Spring request attributes
register(RequestContextFilter.class);
register(SpringComponentProvider.class);
//handles custom serialization
register(new ObjectMapperContextResolver());
//try to register the filters - which doesn't work because these aren't Jersey Filters
register(HystrixRequestContextServletFilter.class);
register(HystrixRequestLogViaResponseHeaderServletFilter.class);
registerResources();
/*
* Enable the logging filter to see the HTTP response for each request.
*/
register(new LoggingFilter(LOGGER, true));
}
}
Servlets and Servlet filters should not be registered in the Jersey config. They will simply be ignored. You should instead be registering them with Spring Boot with ServletRegistrationBeans and FilterRegistrationBeans.
In you Spring configuration, you can do something like
#Bean
public ServletRegistrationBean someServlet() {
ServletRegistrationBean registration = ServletRegisrationBean(
new HystrixMetricsStreamServlet(), "/hystrix.stream");
registration.setName("HystrixMetricsStreamServlet");
return registration;
}
#Bean
public FilterRegistrationBean someFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new HystrixRequestContextServletFilter());
registration.setUrlPatterns(Arrays.asList("/*"));
registration.setName("HystrixRequestContextServletFilter");
// you can also set the order of filters if you need to
return registration;
}
Also:
you don't need to register the SpringComponentProvider. This is automatically registered.
If you get a 404 on trying to access the servlet being registered this way, it will be because you are using the default Jersey mapping /*, which hogs up all the request. You can change the mapping or register Jersey as a filter to forward not found requests. See this post
An alternative route, and the one I ended up eventually going with, is to use the Spring cloud/boot starters if you're in a Spring Boot project. This prevented me from having to explicitly define beans and filters as shown in the other answer. Eventually basically worked out of the box.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<exclusions>
<!--We're running our Jersey server w/ Jackson 2. This import uses Jackson 1.x and creates a breaking conflict.-->
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Reference Circuit Breaker getting started guide. The one issue I faced was the Jackson 1 vs Jackson 2 conflict and was able to add the library exclusion. I basically had the Hystrix library jar before, but nothing wired up to make it work.
Using .net tooling, I have been able create an ODATA service endpoint that exposes a legacy MSSQL database. It was my intent to then use odata4j to communicate to it. However, lacking pojos, I turned to restlet. I made all entities visible in the service, but when I run the restlet generator it fails to generate pojos saying:
java.util.concurrent.TimeoutException
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:230)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
...
Can't get the metadata for `http://localhost:53088/ODataService.svc/`
...
java.io.IOException: Couldn't parse the source representation: java.io.IOException: The thread blocked at the cyclic barrier has timed out.
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:238)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
at xxx.model.generator.ModelGenerator.main(ModelGenerator.java:12)
I decided to trim down the ODATA service to a single simple entity and try the code generation and it worked! But as I enabled more entities, I received an XML parsing error:
Can't get the metadata for `http://localhost:53088/ODataService.svc/`
java.io.IOException: Couldn't parse the source representation:\
org.xml.sax.SAXParseException: XML document structures must start and end within \
the same entity.
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:238)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
at xxx.model.generator.ModelGenerator.main(ModelGenerator.java:12)
An error occurred:
Cannot retrieve the metadata.
Anyways, it seems to dislike the xml after some number of entities, rather than disliking a specific entity. Also the XML from http://localhost:53088/ODataService.svc/$metadata is valid with no errors.
Here is the Generator code:
import org.restlet.ext.odata.Generator;
public class ModelGenerator
{
public static final String [] URL_WORKSPACE = { "http://localhost:53088/ODataService.svc/", "src/main/java/"};
public static void main(String[] args)
{
Generator.main(URL_WORKSPACE);
}
}
Here are my maven POM details:
<properties>
<org.odata4j.version>0.7.0</org.odata4j.version>
<org.restlet.version>2.1.4</org.restlet.version>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.odata4j</groupId>
<artifactId>odata4j-core</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet</artifactId>
<version>${org.restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.odata</artifactId>
<version>${org.restlet.version}</version>
</dependency>
</dependencies>
Any suggestions would be appreciated. Thank you!
I am trying to save data on my database with a web service POST wich serializes a HTML form to save a object. The rest client firefox says this:
"The server refused this request because the requested entity is in a format not supported by the requested resource for the requested method"
The eclipse console shows the message:
org.jasig.cas.client.util.CommonUtils - safeGetParameter called on a POST HttpServletRequest for LogoutRequest. Cannot complete check safely. Reverting to standard behavior for this Parameter
I understand that the object that i want to save is not valid, but I don't see what the problem is.
#RequestMapping(value="/solicitudCita", method = RequestMethod.POST)
public #ResponseBody String putSolicitud(#ModelAttribute("Solicitud") Solicitud solicitud) throws Exception{
System.out.println(solicitud.toString());
solicitudCitaAppMService.createOrUpdate(solicitud);
String solicitudAdded = "Solicitud de cita -> {" + solicitud.toString() + "} aƱadida";
System.out.println(solicitud);
return solicitudAdded;
}
Help me please
Thanks
If you want to call this controller in a RESTful manner, you have to annotate the solicitud parameter as #RequestBody. Second, you have to have the Jackson libraries in you classpath so Spring can pick them up and use them for unmarshalling the object.
If you use Maven, use these dependencies:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
BTW, why do you have to serialize the HTML form and sent it across? I would suggest you use a REST client, for instance this one, that is available in the Chrome WebStore.