Using google-http-client to upload files via API - java

I'm trying to upload a file ("new.html", in the root of my project directory) via an API using Google's http-client.
The docs for the API (and the specific function) can be found at https://piathome.com/apidocs/#/asset/UploadFile.
My code is as follows
FileContent fileContent = new FileContent("text/html", new File("new.html"));
MultipartContent mpc = new MultipartContent().setMediaType(new HttpMediaType("multipart/form-data")
.setParameter("boundary", "__END_OF_PART__"));
MultipartContent.Part part = new MultipartContent.Part(fileContent);
part.setHeaders(new HttpHeaders().set("Upload ", "file=#new.html;type=text/html"));
mpc.addPart(part);
HttpRequest request;
try {
request = requestFactory.buildPostRequest(new GenericUrl(baseURL + "/files"), mpc)
.setParser(JsonFactory.createJsonObjectParser());
request.getHeaders().set("x-access-token", token);
request.getHeaders().set("accept", "application/json");
HttpResponse response = request.execute();
System.out.println(response.parseAsString());
Printing out response.parseAsString() yields {"stat_message":" Successfully uploaded files","data":[],"success":true}. Obviously something is wrong here, as the data field of the response is empty, but I'm not sure what I'm doing wrong, or why the API is returning success when something isn't working.
Any help is appreciated, thanks.

Related

How to create a POST request for a file upload

I am currently uploading some files via the API from Opentext Content Server 21.2. I have already implemented most of the method calls. I can upload files, create folders, delete files and so on. However, I am currently failing with the file upload. Mainly only PDFs or images (Jpeg, PNG etc.) should be uploaded.
The current API documentation can be found here:
https://developer.opentext.com/apis/14ba85a7-4693-48d3-8c93-9214c663edd2/d7540c64-7da2-4554-9966-069c56a9341d/a35ce271-5bb7-4bcf-b672-0c8bcf747091#operation/createNode2
My current code looks like this:
#Override
public ClientResponse saveFile(String sessionId, String folderId, File document, String filename) throws DmsException, IOException {
client = ClientHelper.createClient();
client.addFilter(new LoggingFilter());
Builder webResource = client.resource(getRestUri() + REST_CREATE).header("otcsticket", sessionId);
MultivaluedMap<String, String> postBody = new MultivaluedMapImpl();
postBody.add("name", filename);
postBody.add("type", TYPE_FILE);
postBody.add("parent_id", folderId);
postBody.add("file", FileUtils.readFileToString(document, StandardCharsets.UTF_8));
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).post(ClientResponse.class, postBody);
if (response.getStatus() == 200) {
return response;
} else {
System.out.println(response.toString());
System.out.println(response.getEntity(String.class));
throw new DmsException("XYZ-001", XYZ: HTTP-CODE "
+ response.getStatusInfo().getStatusCode() + " - " + response.getStatusInfo().getReasonPhrase());
}
}
The code returns a HTTP-STATUS 200 OK. However, no file is created, but a folder is created. The API description for this is identical only with the difference that no file is passed. Therefore I assume that the file parameter is skipped.
PS: I am using Jersey 1.19.1
I ask for help and am grateful for any answer

inexperienced in java. Fumbling my way through a REST API client

I'm cobbling a small android app together that I want to use for our team. All it is doing is calling to a REST API endpoint and hitting a bunch of queries. Status, alerts, some monitoring information. Pretty simple. But I have spent 3 days staring at every site on Google that explains how to make a REST API call in Java, get back the JSON, and then store it as something like a hash where I can then just reference the JSON elements by name. I wrote a desktop version in Python and I'm thinking something like where Python just parses it into a DICT. So far I have some code. I'm not even sure if it works because I'm stuck with what to do next:
protected void getJSON() {
String url = "http://192.168.8.29/api/v1/version";
try {
URL hmAPIEndPoint = new URL(url);
HttpURLConnection myConnection = (HttpURLConnection) hmAPIEndPoint.openConnection();
if (myConnection.getResponseCode() == 200) {
// Success
// Further processing here
Log.d("getJSON", "Got a 200 back from the openConnection()");
InputStream responseBody = myConnection.getInputStream();
InputStreamReader responseBodyReader = new InputStreamReader(responseBody, "UTF-8");
JsonReader jsonReader = new JsonReader(responseBodyReader);
// I need jsonReader to be something I can reference like jsonReader['version_id']
jsonReader.close();
myConnection.disconnect();
} else {
Log.e("getJSON", "Didn't register a 200 response. Actual: " + myConnection.getResponseCode());
}
} catch (MalformedURLException mfe) {
Log.e("getJSON", mfe.getStackTrace().toString());
} catch (Exception e) {
Log.e("getJSON", e.getStackTrace().toString());
}
}
From here there are like 500 sites that tell me to just parse the json line by line but that seems... stupid. Is there a way that I can get the jsonReader thing into an object like a described above?
Thanks in advance for your help.
Option 1
You can go with Retrofit network library.
It will convert all your json to POJO.
Sample tutorial
https://medium.com/#prakash_pun/retrofit-a-simple-android-tutorial-48437e4e5a23
Option 2
Try to convert inputstream to POJO with help of GSON library
Gson dependency
implementation 'com.google.code.gson:gson:2.8.5'
Sample tutorial
http://www.acuriousanimal.com/2015/10/23/reading-json-file-in-stream-mode-with-gson.html

How to display captcha in ImageView in Android.?

I have a PNR Inquiry app on Google Play. It was working very fine. But recently Indian Railwys added captcha to their PNR Inquiry section and because of this I am not able to pass proper data to the server to get proper response. How to add this captcha in my app in form of an imageview and ask the users to enter captcha details also so that I can send proper data and get proper response.
Indian Railways PNR Inquiry Link
If you check the html code, its actualy pretty bad captcha.
Background of captcha is: http://www.indianrail.gov.in/1.jpg
Those numbers are actualy in input tag:
<input name="lccp_cap_val" value="14167" id="txtCaptcha" type="hidden">
What they are doing is, via javascript, use numbers from that hidden input tag
and put them on that span with "captcha" background.
So basicaly your flow is:
read their html
get "captcha" (lol, funny captcha though) value from input field
when user puts data in your PNR field and presses Get Status
post form field, put PNR in proper value, put captcha in proper value
parse response
Oh yeah, one more thing. You can put any value in hidden input and "captcha"
input, as long as they are the same. They aren't checking it via session or
anything.
EDIT (code sample for submiting form):
To simplify posting form i recommend HttpClient components from Apache:
http://hc.apache.org/downloads.cgi
Lets say you downloaded HttpClient 4.3.1. Include client, core and mime
libraries in your project (copy to libs folder, right click on project,
properties, Java Build Path, Libraries, Add Jars -> add those 3.).
Code example would be:
private static final String FORM_TARGET = "http://www.indianrail.gov.in/cgi_bin/inet_pnstat_cgi.cgi";
private static final String INPUT_PNR = "lccp_pnrno1";
private static final String INPUT_CAPTCHA = "lccp_capinp_val";
private static final String INPUT_CAPTCHA_HIDDEN = "lccp_cap_val";
private void getHtml(String userPnr) {
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody(INPUT_PNR, userPnr); // users PNR code
builder.addTextBody(INPUT_CAPTCHA, "123456");
builder.addTextBody("submit", "Get Status");
builder.addTextBody(INPUT_CAPTCHA_HIDDEN, "123456"); // values don't
// matter as
// long as they
// are the same
HttpEntity entity = builder.build();
HttpPost httpPost = new HttpPost(FORM_TARGET);
httpPost.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = null;
String htmlString = "";
try {
response = client.execute(httpPost);
htmlString = convertStreamToString(response.getEntity().getContent());
// now you can parse this string to get data you require.
} catch (Exception letsIgnoreItForNow) {
}
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException ignoredOnceMore) {
} finally {
try {
is.close();
} catch (IOException manyIgnoredExceptions) {
}
}
return sb.toString();
}
Also, be warned i didn't wrap this in async call, so you will have to do that.
Image from the network can be displayed in android via efficient image loading api's like Picasso/volley or simply image view via async task.
considering all above things as basic build a logic such that you should need a image URL for that captcha if user resets or refresh the captcha it should reload new image via network call requesting the new request implementation, you have to get REST api access to the Indian railway and check in that any image uri available in that (it may be in base64 format )
if REST API is not available you may think of building your own server with this code
RESTful API to check the PNR Status
pnrapi
Update: you don't need to do this complex hacks , just implement Drago's answer !

multipart form data in javascript with java server using FileUpload

I try to send a multipart form data with a file by using only javascript. I write the request myself. So my javascript code is the following :
var data =
'------------f8n51w2QYCsvNftihodgfJ\n' +
'Content-Disposition: form-data; name="upload-id"\n' +
'\n' +
'uploadedFiles\n' +
'------------f8n51w2QYCsvNftihodgfJ\n' +
'Content-Disposition: form-data; name="file"; filename="doc1.txt"\n' +
'Content-Type: text/plain\n' +
'\n' +
'azerty\n' +
'------------f8n51w2QYCsvNftihodgfJ--\n';
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=----------f8n51w2QYCsvNftihodgfJ');
xhr.sendAsBinary(data);
I run this javascript on Firefox 18.
So i got a servlet on /upload. Here's the code :
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestContext request_context = new ServletRequestContext(request);
boolean is_multipart = ServletFileUpload.isMultipartContent(request_context);
if (is_multipart) {
FileUpload file_upload = new FileUpload(fileItemFactory);
List<FileItem> file_items = file_upload.parseRequest(request_context); // This line crash
}
}
As the comment says, the line file_upload.parseRequest(request_context); crash and throws the following exception :
org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream.readHeaders(MultipartStream.java:539)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:976)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:942)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:349)
And i just don't know why i got this exception ... Any idea ?
It seems like MultipartStream can't find the request headers. But if i log the headers, they are all here and they are correct.
My servlet code works with a "normal" form. I tried to log the request body and headers of a normal form, and they are the same (except the boundary, of course).
I also tried to change the data variable with a invalid content. The error is still the same, so there's definitively a problem with my headers but i don't see what.
I found the solution.
\n IS NOT a valid separator for multipart form. You must use \r\n. Now my code works properly.
I don't understand why you use sendAsBinary. If not absolutely necessary I wouldn't assemble the payload (data variable) myself but use FormData.
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects
var oMyForm = new FormData();
oMyForm.append("username", "Groucho");
oMyForm.append("accountnum", 123456); // number 123456 is immediately converted to string "123456"
// HTML file input user's choice...
oMyForm.append("userfile", fileInputElement.files[0]);
// JavaScript file-like object...
var oFileBody = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file...
var oBlob = new Blob([oFileBody], { type: "text/xml"});
oMyForm.append("webmasterfile", oBlob);
var oReq = new XMLHttpRequest();
oReq.open("POST", "http://foo.com/submitform.php");
oReq.send(oMyForm);
try change f8n51w2QYCsvNftihodgfJ to f8n51w2QYCsvNftihodgfM
I've tried running your code with different random boundaries and turn out only f8n51w2QYCsvNftihodgfJ\n got issue. I reckon you can try a different boundary, since it is really just a random string.

Async urlfetch Http post on App engine using Future

My goal is to rapidly make posts to a server from appengine(java). I am attempting to do this using UrlFetchService.fetchAsync. I have been basing my code after this blog post. I have been able to make the request using the code below, however I get some strange behavior:
private void futureRequests() {
URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
URL url = new URL("https://someserver.com");
FetchOptions fetchOptions = FetchOptions.Builder.withDefaults();
fetchOptions.doNotValidateCertificate();
fetchOptions.setDeadline(60D);
ArrayList<Future<HTTPResponse>> asyncResponses = new ArrayList<Future<HTTPResponse>>();
for (int i = 0; i < postDatas.size(); i++) {
HTTPRequest request = new HTTPRequest(url, HTTPMethod.POST, fetchOptions);
request.setPayload(postDatas.get(i).getBytes(UTF8));
HTTPHeader header = new HTTPHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
request.setHeader(header);
header = new HTTPHeader("Content-Length", Integer.toString(postDatas.get(i).getBytes().length));
request.setHeader(header);
header = new HTTPHeader("Authorization", "auth=" + authToken);
request.setHeader(header);
Future<HTTPResponse> responseFuture = fetcher.fetchAsync(request);
asyncResponses.add(responseFuture);
}
for (Future<HTTPResponse> future : asyncResponses) {
HTTPResponse response;
try {
response = future.get();
int responseCode = response.getResponseCode();
resp.getWriter().println("response: " + responseCode);
logger.warning("Response: " + responseCode);
} catch (Exception e) {
}
}
}
The strange behavior is that I get duplicate posts on the server, and according to my appstats page I use 10x-20x more urlFetches than what was added with the code above. Below is my appstats screen:
There are more urlFetch calls that could not fit on the screen. It appears that the requests are still completing in a synchronous fashion(circled items), but there are many urlFetches that appear to go on at the same time. My question is how am I getting all this calls to urlFetch when I only had 14 Future ?? Could the server be giving an error or 503 and urlFetch retrying until it goes through? And how can I be getting 2 posts for each request??
I understand that I could use the task queue to do asyc request, however I am dealing with a relatively low number of request(20-100) and the cold start time of ramping up another instance would probably make this not a good option for my situation. Can anyone explain this behavior or have experience with this?
This was simply a mistake in my code that was causing my app to make more request than I thought..

Categories

Resources