How to create API that accepts InputStream as a parameter? - java

My grails 2.2.4 app needs to support accepting files over HTTP from a third party application and sending the file, after making some tweaks to it, back out as a response to the third party application.
I want to convert the data sent by the third party application to a file using InputStream and then send the file back out using OutputStream
So I built this code:
API Classes
class ApiResponse {
ApiMeta meta
ApiObject apiObj
}
class ApiMeta {
int code
String errorType
List msgs = []
}
class ApiObject {
OutputStream os
}
//Object Marshaller
JSON.registerObjectMarshaller( ApiObject ) { ApiObject obj ->
//How can I send output stream as json?
}
Controller
//controller
def save() {
request.withFormat {
json {
ApiResponse resp
//How can I convert the JSON data in params to a file?
response.status = 201
resp = new ApiResponse(
meta: new ApiMeta(code: 201),
apiObj: new ApiObject(os: transfers))
render resp as JSON
}
multipartForm {
}
}
Question
How can I convert JSON payload sent by the third party service into a file?
Is it ok to put OutputStream in my ApiObject class so that I can send the JSON payload back to the service?

My grails 2.2.4 app needs to support accepting InputStream over HTTP
from a third party application and sending OutputStream as a response
back.
That does not really make sense. Third party apps can't really send an InputStream to your app and your app can't really send an OutputStream back. The third party app can send you data in the body of the request and you can read the body by retrieving an InputStream from the request, and the same sort of thing could happen when you put data in the response. At first read I thought maybe you were just wording things in a way that doesn't make sense but then when I saw your domain class, that suggests that maybe you really are confused about how this works.
class Request {
InputStream instream
OutputStream outstream
static constraints = {
instream nullable: false, blank: false
}
}
You can't do that. You cannot persist an InputStream or an OutputStream to the database.
EDIT:
If you have a controller like this:
class MyController {
def someAction(Widget w) {
// do whatever you need to do with the Widget
}
}
class Widget {
String name
String category
}
And you send a request to that controller action with a JSON body which looks like this...
{"name":"Robert","category":"Prog Rocker"}
Grails will automatically read the body of the request and do the corresponding binding. You would never have to directly interact with any input stream to make that happen. Is that the sort of thing you are looking for?

Related

Sending Inputstream in spring integration

I have a project where I want to sending a pdf file to an ftp server.
I am creating the file using pdfbox and changing it to an Inputstream and then I was to pass this input scream value to a remote FTP and save it as .pdf.
I have the below code but not sure how I can pass the data to the outbound adapter.
#Bean
public IntegrationFlow localToFtpFlow() {
return IntegrationFlows.from("toFtpChannel")
.handle(Ftp.outboundAdapter(sf())
.remoteDirectory("/ftp/forklift_checklist"))
.get();
}
#MessagingGateway
public interface MyGateway {
#Gateway(requestChannel = "toFtpChannel")
void sendToFtp(InputStream file);
}
Not sure what why is the question.
What you have so far is OK:
You call that sendToFtp() gateway's method with an InputStream for a local file.
The Ftp.outboundAdapter(sf() is based on the this.remoteFileTemplate.send(message, this.mode) operation which really supports an InputStream for a request payload:
else if (payload instanceof InputStream) {
return new StreamHolder((InputStream) payload, "InputStream payload");
}
So, share with us, please, what the problem are you observing with your configuration?
Perhaps you are looking into a fileName to give for that data while saving to FTP. Consider to have another gateway argument as a #Header(FileHeaders.FILENAME) String fileName. The RemoteFileTemplate relies on a DefaultFileNameGenerator which looks into that header by default.

How to read body of HttpServletRequest multiple times?

Basically I need to read the body of HttpServletRequest multiple times, based on my research I found that one of easiest way for doing that is by using ContentCachingRequestWrapper
Here is how I implemented it:
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
try{
MultipartRequest multipartRequest = new MultipartRequest(requestWrapper, ImageDirecoty, 1024*1024*5);
String test = requestWrapper.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.print(test);
} catch(IOException e){
System.out.println(e.getMessage());
return;
}
FYI: I am uploading a simple file from my client to server.
Now at first it reads the request body just fine, but in the second line which I have String test = requestWrapper to read it's content and to output it to console I don't get my Ecplise console outputing me anything and I don't get any error too, I'd really appreciate if somebody tell me what am i doing wrong.
actually the easy est way to do it is to use(convert the response), to some kind of Pojo class, and then saving it to whatever you want.
here is a link to convert it to pojo
http://www.jsonschema2pojo.org/
also you can use library's like Retrofit 2.0 to make your http calls much easier.
http://square.github.io/retrofit/

How to Create a Restful service for already available site

I have some API web site which will generate some JSON data but I can't access that data directly with that URL (if I try to access it says oauth error) so for that I have a secret key and lib file which throws that exception.
So I want to create a Restful web service for that ,...
without the restful service, I am accessing the data from a class file which invoked in main() method and if I run it as java application I am getting data at console,.. hence it has main method,..
but I need to build a Restful web service,. and retrieve the data in mobile windows/iPhone/android
I know what is Restful service But I don't know how get that data java file data,.. which is at console,...to Restful service
Try this
you have code the below stuff in your webservice method
public String myMethos(){
String urlString="http://example.com/WS/StaticExample.php?method=sayHello&name=World";
URL url=new URL(urlString);
URLConnection connection=url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.close();
JSONObject jsonobj = null;
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String decodedString="",URLstrJson="";
while ((decodedString = in.readLine()) != null) {
URLstrJson+=decodedString;
}
Say your value of URLstrJson is as shown below
{
"worldpopulation":
[
{
"rank":1,
"country":"China",
"population":"1,354,040,000",
"flag":"http://www.androidbegin.com/tutorial/flag/china.png"
}
]
}
Then,
jsonobj=new JSONObject(URLstrJson);
System.out.println(jsonobj.toString());
return jsonobj.toString();
}
With what I percieve from your problem, you can write a wrapper REST class which calls your current methods and send back the response to user. Elaborating it, say your current class is A and its method is getData(), which is currently called from main method. Now you create a REST class with a method say data() and within this function you are just doing return A.getData().
Other configurations like annotations, param types etc. you can add as per you needs.

How to call a URL with params and get back response in servlet?

I have a situation where a intermediate servlet needs to be introduced which will handle requests from existing project and redirect the manipulated response to either existing project or the new one. This servlet will act as an interface to login into the new project from some other application.
So currently I use the following code to get back response in jsp as an xml.
var jqxhr =$.post("http://abhishek:15070/abc/login.action",
{ emailaddress: "ars#gmail.com",
projectid: "123" },
function(xml)
{
if($(xml).find('isSuccess').text()=="true")
{
sessiontoken=$(xml).find('sessiontoken').text();
setCookie("abcsessionid", sessiontoken , 1);
setCookie("abcusername",e_add,1);
}
}
)
.error(function() {
if(jqxhr.responseText == 'INVALID_SESSION') {
alert("Your Session has been timed out");
window.location.replace("http://abhishek:15070/abc/index.html");
}else {
alert( jqxhr.responseText);
}
});
xml content
<Response>
<sessiontoken>334465683124</sessiontoken>
<isSuccess>true</isSuccess>
</Response>
but now I want the same thing to be done using servlet, is it possible?
String emailid=(String) request.getParameter("emailaddress");
String projectid=(String) request.getParameter("projectid");
Update
I just came up with something.
Is it possible to return back a html page with form (from servlet), whose on body load it will submit a form and on submission of this form it will receive the response xml which will get processed.
Use java.net.URLConnection or Apache HttpComponents Client. Then, parse the returned HTTP response with a XML tool like as JAXB or something.
Kickoff example:
String emailaddress = request.getParameter("emailaddress");
String projectid = request.getParameter("projectid");
String charset = "UTF-8";
String query = String.format("emailaddress=%s&projectid=%s",
URLEncoder.encode(emailaddress, charset),
URLEncoder.encode(projectid, charset));
URLConnection connection = new URL("http://abhishek:15070/abc/login.action").openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
try {
connection.getOutputStream().write(query.getBytes(charset));
}
finally {
connection.getOutputStream().close();
}
InputStream response = connection.getInputStream();
// ...
See also:
Using java.net.URLConnection to fire and handle HTTP requests
HttpClient tutorial and examples
Actually, what you probably want is not an intermediate servlet at all. What you probably want is called a servlet filter and writing one is not particularly hard. I've written one in the past and I just started on a new one yesterday.
An article like this one or this one lays out pretty simply how you can use a servlet filter to intercept calls to specific URLs and then redirect or reject from there. If the incoming URL matches the pattern for the filter, it will get a shot at the request and response and it can then make a choice whether or not to pass it on to the next filter in line.
I don't know if all third party security solutions do it like this, but at least CAS seemed to be implemented that way.

Download dynamic file with GWT

I have a GWT page where user enter data (start date, end date, etc.), then this data goes to the server via RPC call. On the server I want to generate Excel report with POI and let user save that file on their local machine.
This is my test code to stream file back to the client but for some reason I think it does not know how to stream file to the client when I'm using RPC:
public class ReportsServiceImpl extends RemoteServiceServlet implements ReportsService {
public String myMethod(String s) {
File f = new File("/excelTestFile.xls");
String filename = f.getName();
int length = 0;
try {
HttpServletResponse resp = getThreadLocalResponse();
ServletOutputStream op = resp.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
resp.setContentType("application/octet-stream");
resp.setContentLength((int) f.length());
resp.setHeader("Content-Disposition", "attachment; filename*=\"utf-8''" + filename + "");
byte[] bbuf = new byte[1024];
DataInputStream in = new DataInputStream(new FileInputStream(f));
while ((in != null) && ((length = in.read(bbuf)) != -1)) {
op.write(bbuf, 0, length);
}
in.close();
op.flush();
op.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
return "Server says: " + filename;
}
}
I've read somewhere on internet that you can't do file stream with RPC and I have to use Servlet for that. Is there any example of how to use Servlet and how to call that servlet from ReportsServiceImpl. Do I really need to make a servlet or it is possible to stream it back with my RPC?
You have to make a regular Servlet, you cannot stream binary data from ReportsServiceImpl. Also, there is no way to call the servlet from ReportsServiceImpl - your client code has to directly invoke the servlet.
On the client side, you'd have to create a normal anchor link with the parameters passed via the query string. Something like <a href="http://myserver.com/myservlet?parm1=value1&.."</a>.
On the server side, move your code to a standard Servlet, one that does NOT inherit from RemoteServiceServlet. Read the parameters from the request object, create the excel and send it back to the client. The browser will automatically popup the file download dialog box.
You can do that just using GWT RPC and Data URIs:
In your example, make your myMethod return the file content.
On the client side, format a Data URI with the file content received.
Use Window.open to open a file save dialog passing the formatted DataURI.
Take a look at this reference, to understand the Data URI usage:
Export to csv in jQuery
It's possible to get the binary data you want back through the RPC channel in a number of ways... uuencode, for instance. However, you would still have to get the browser to handle the file as a download.
And, based on your code, it appears that you are trying to trigger the standard browser mechanism for handling the given mime-type by modifying the response in the server so the browser will recognize it as a download... open a save dialog, for instance. To do that, you need to get the browser to make the request for you and you need the servlet there to handle the request. It can be done with rest urls, but ultimately you will need a serviet to do even that.
You need, in effect, to set a browser window URL to the URL that sends back the modified response object.
So this question (about streaming) is not really compatible with the code sample. One or the other (communication protocols or server-modified response object) approach has to be adjusted.
The easiest one to adjust is the communication method.

Categories