Our team has developed Server-Sent events (SSE) for a specific task.
I am trying to build a client to listen to event streams from our server.
I have sort of managed to do this using the Jersey libraries for Java.
However since most of our client code uses Spring, I would like to have an example of how this could be done using Spring.
I was able to find many examples on SSE on the server side for Spring. However I am unable to find any documentation for the client side.
Does Spring support SSE on the client side?
If yes, may I have an example of how the following can be achieved using Spring...
Send an HTTP GET request to our server...
GET -> http://example.com/api/events/
headers ->
Accept:text/event-stream
sessionKey:someString
The response will be a text stream, that the client will continue to receive, until the client chooses to close the connection.
Have a look at one of the execute methods of the Spring RestTemplate. They all take a ResponseExtractor as parameter. This callback interface defines one method: extractData(ClientHttpResponse response). By providing your own ResponseExtractor you can do what you want with the response, like reading from it line-by-line. Naive example:
restTemplate.execute(a_url, HttpMethod.GET, request -> {
}, response -> {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody()));
String line;
try {
while ((line = bufferedReader.readLine()) != null) {
System.out.println("Got some data, let's use my ObjectMapper to parse into something useful!");
}
} catch (IOException e) {
//Something clever
}
return response;
});
Related
I am working in a project where a request(ISO 8583) need to be send via JPOS server to the backed (Remote Host as per official doc) via SOAP api.
We have implemented our system as follows:
We implemented a ISOListner in a middle ware(spring boot project) where it converts the incoming ISO message to SOAP request.
Is it possible to embed the Middle ware code to JPOS server itself and omit the mw?
If possible , what is the right place to put our conversion logic ?
Is it the ChannelAdaptor or TransactionManager ?
Few blogs suggest that we can put all logic to TransactionManager or ChannelAdaptor. If it is true
then why we need mux and channel at all? Or our architecture is ok to proceed further ?
For the sake of completeness I will include the answer to this question that was also asked in jPOS Users group (https://groups.google.com/forum/#!topic/jpos-users/PGzb4syQRzs):
We usually implement a custom participant doing the SOAP/REST thing.
In the case of REST, we use Apache's HTTP Client
(org.apache.httpcomponents:httpclient:4.5.5) that provides a nice
async interface that works great with the TransactionManager's PAUSE.
Here is an example:
public int prepare (long id, Serializable o) {
Context ctx = (Context) o;
String url = getURL (ctx);
HttpPost post = new HttpPost(url);
StringEntity entity = new StringEntity(ctx.getString(JSON_REQUEST.name()),ContentType.create("application/json", Consts.UTF_8));
post.setEntity(entity);
try {
client.execute(post, response -> {
int sc = response.getStatusLine().getStatusCode();
if (sc == HttpStatus.SC_CREATED || sc == HttpStatus.SC_OK)
ctx.put (JSON_RESPONSE.name(), EntityUtils.toString(response.getEntity()));
ctx.resume();
return null;
});
return PREPARED | PAUSE | NO_JOIN | READONLY;
} catch (IOException e) {
warn (e);
}
return ABORTED;
}
TransactionManager is the right place to add custom logic. I guess your are using mux and channel to send iso message to MW socket listener component. Which can be avoided by using a middleware like rabbitmq to connect to backend servers.
For example isomessage in transaction manager can be converted to json and send it to backend server using mq.
When I send a request using a proxy client, if I get a certain response, I would like to be able to modify the request and then send the same request again for all requests.
Normally I would do something like:
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
try
{
proxy.getBook("someId");
}
catch(WebApplicationException ex)
{
Response r = ex.getResponse();
if (r.getStatusCode() == 404)
{
proxy.getBook("anotherId");
}
}
But in this case, there is a common thing I want to do for all requests: If I get a specific http code, modify some header values, and then try again (probably with a limit on the amount of retries).
I haven't seen a way that cxf proxy clients explicitly support this, how could I go about implementing it?
You need to write an interceptor to do this for every request.
here you go for sample code and documentation http://cxf.apache.org/docs/jax-rs-filters.html
Have a Spring Rest application that run inside an embedded Jetty container.
On Client I use RestTemplate(try to).
Use case :
Having an InputStream (I don't have the File), I want to send it to the REST service.
The InputStream can be quite large (no byte[] !).
What I've tried so far :
Added StandardServletMultipartResolver to the Dispatcher context;
On servlet registration executed :
ServletRegistration.Dynamic dispatcher = ...
MultipartConfigElement multipartConfigElement = new MultipartConfigElement("D:/temp");
dispatcher.setMultipartConfig(multipartConfigElement);
On client :
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("attachmentData", new InputStreamResource(data) {
// hacks ...
#Override
public String getFilename() {
//avoid null file name
return "attachment.zip";
}
#Override
public long contentLength() throws IOException {
// avoid calling getInputStream() twice
return -1L;
}
}
ResponseEntity<Att> saved = restTemplate.postForEntity(url, parts, Att.class)
On server :
#RequestMapping("/attachment")
public ResponseEntity<Att> saveAttachment(#RequestParam("attachmentData") javax.servlet.http.Part part) {
try {
InputStream is = part.getInputStream();
// consume is
is.close();
part.delete();
return new ResponseEntity<Att>(att, HttpStatus.CREATED);
}
}
What is happening :
The uploaded InputStream is stored successfully in the configured temp folder (MultiPart1970755229517315824), the Part part parameter is correctly Injected in the handler method.
The delete() method does not delete the file (smth still has opened handles on it).
Anyway it looks very ugly.
Is there a smoother solution ?
You want to use HTTP's Chunked Transfer Coding. You can enable that by setting SimpleClientHttpRequestFactory.setBufferRequestBody(false). See SPR-7909.
You should rather use byte[], and write a wrapper around the webservice to actually send the "large string" in chunks. Add a parameter in the webservice which will indicate the "contentID" of the content, so that the other side knows this part belongs to which half-filled "bucket". Another parameter "chunkID" would help in sequencing of the chunks on the other side. Finally, third parameter, "isFinalChunk" would be set if whatever you are sending is the final thing. This is pretty non-fancy functionality achievable in less than 100 lines of code.
The only issue with this is that you end up making "n" calls to the webservice rather than just one call, which would aggregate the connect delays etc. For realtime stuff, some more network QoS is required, but otherwise you should be fine.
I think this is much simpler, and once you have your own class wrapper to do this simple chopping and gluing, it is scalable to a great extent if your server can handle multiple webservice calls.
I am trying to get the raw XML response from a web service, instead of the usual set of POJOs.
I am using a webservice client that I generated (so I have access to the client's code) from a WSDL and some schemas. The client is generated in RAD 7.5, I think using JAX-WS. I've been looking at the client code itself, but I'm not even sure if the client code ever handles raw XML or if it passes it off to other libraries.
You can do it using
javax.xml.ws.handler.soap.SOAPHandler<javax.xml.ws.handler.soap.SOAPMessageContext>
you can simply get message using SOAPMessageContext#getMessage() and convert message to String using method
public static String getXmlMessage(SOAPMessage message) throws Exception
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
message.writeTo(os);
final String encoding = (String) message.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
if (encoding == null)
{
return new String(os.toByteArray());
}
else
{
return new String(os.toByteArray(), encoding);
}
}
Also you can read here about SOAP handler on client side
Article
It's not widely documented, but you can use the Dispatch interface to implement JAXWS clients which work directly w/ the XML. Here and here are some articles for getting started.
I am using Spring with DWR . I want to return a file object as response , however I save the file (to be sent) at server temporary location and then send its location as href for anchor tag on client side , however I wonder if there could be a way to throw the file directly to browser on response object without saving it temporarily on server.
I expected if there could be a way to send file as a response via DWR.
public ModelAndView writeFileContentInResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileInputStream inputStream = new FileInputStream("FileInputStreamDemo.java"); //read the file
response.setHeader("Content-Disposition","attachment; filename=test.txt");
try {
int c;
while ((c = inputStream.read()) != -1) {
response.getWriter().write(c);
}
} finally {
if (inputStream != null)
inputStream.close();
response.getWriter().close();
}
}
It has been years since I've used Spring, and I'm unfamiliar with DWR, but the essence of your question is basic to the web.
The answer is yes, you can. In effect, you need to set the HTTP header Content-Disposition: attachment, then stream down the contents. All of this will be in the response to the original request (as opposed to sending back a link).
The actual code to achieve this will depend on your circumstances, but this should get you started.
you call the method from Java Script, right? I didn't really understand how Spring is related in this flow, but as far as I know DWR allows you to produce Java Script Stubs and call the Java methods of the exposed bean directly on server right from your java script client code.
You can read the file byte-by-byte and return it from your java method as long as it really returns a byte array.
However what would you do with this byte array on client?
I just think in this specific flow you shouldn't use the DWR but rather issue an ordinar AJAX request (if DWR can wrap it somehow for convenience - great). This request shouldn't come to DWRServlet, but rather be proceeded by a regular servlet/some web-based framework, like Spring MVC :)
Once the request comes to the servlet, use
response.setHeader("Content-Disposition","attachment; filename=test.txt");
as was already stated.
Hope this helps,
Good luck!
Mark
An example which return a excel to download from client:
//Java side:
public FileTransfer getExcel(Parametros param){
byte[] result = <here get data>;
InputStream myInputStream = new ByteArrayInputStream(result);
String excelFormat = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
FileTransfer dwrExcelFile = new FileTransfer("excel.xlsx", excelFormat, myInputStream);
return dwrExcelFile;
}
//Javascript side:
function downloadExcelFile() {
dwr.engine.setTimeout(59000);
var params = <params_to_send>;
<Java_class>.getExcel(params, {callback:function(dataFromServer) {
downloadExcelCallback(dataFromServer);
}});
}
function downloadExcelCallback(data) {
dwr.engine.openInDownload(data);
}