3

I have to upload a file to a server which only exposes a jsf web page with file upload button (over http). I have to automate a process (done as java stand alone process) which generates a file and uploads the file to the server.Sadly the server to where the file has to be uploaded does not provide a FTP or SFTP. Is there a way to do this?

Thanks, Richie

Richie
  • 8,436
  • 4
  • 22
  • 37

5 Answers5

7

When programmatically submitting a JSF-generated form, you need to make sure that you take the following 3 things in account:

  1. Maintain the HTTP session (certainly if website has JSF server side state saving turned on).
  2. Send the name-value pair of the javax.faces.ViewState hidden field.
  3. Send the name-value pair of the button which is virtually to be pressed.

Otherwise the action will possibly not be invoked at all. For the remnant it's not different from "regular" forms. The flow is basically as follows:

  • Send a GET request on the page with the form.
  • Extract the JSESSIONID cookie.
  • Extract the value of the javax.faces.ViewState hidden field from the response. If necessary (for sure if it has a dynamically generated name and thus possibly changes every request), extract the name of input file field and the submit buttonas well. Dynamically generated IDs/names are recognizeable by the j_id prefix.
  • Prepare a multipart/form-data POST request.
  • Set the JSESSIONID cookie (if not null) on that request.
  • Set the name-value pair of javax.faces.ViewState hidden field and the button.
  • Set the file to be uploaded.

You can use any HTTP client library to perform the task. The standard Java SE API offers java.net.URLConnection for this, which is pretty low level. To end up with less verbose code, you could use Apache HttpClient to do the HTTP requests and manage the cookies and Jsoup to extract data from the HTML.

Here's a kickoff example, assuming that the page has only one <form> (otherwise you need to include an unique identifier of that form in Jsoup's CSS selectors):

String url = "http://localhost:8088/playground/test.xhtml";
String viewStateName = "javax.faces.ViewState";
String submitButtonValue = "Upload"; // Value of upload submit button.

HttpClient httpClient = new DefaultHttpClient();
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore());

HttpGet httpGet = new HttpGet(url);
HttpResponse getResponse = httpClient.execute(httpGet, httpContext);
Document document = Jsoup.parse(EntityUtils.toString(getResponse.getEntity()));
String viewStateValue = document.select("input[type=hidden][name=" + viewStateName + "]").val();
String uploadFieldName = document.select("input[type=file]").attr("name");
String submitButtonName = document.select("input[type=submit][value=" + submitButtonValue + "]").attr("name");

File file = new File("/path/to/file/you/want/to/upload.ext");
InputStream fileContent = new FileInputStream(file);
String fileContentType = "application/octet-stream"; // Or whatever specific.
String fileName = file.getName();

HttpPost httpPost = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
entity.addPart(uploadFieldName, new InputStreamBody(fileContent, fileContentType, fileName));
entity.addPart(viewStateName, new StringBody(viewStateValue));
entity.addPart(submitButtonName, new StringBody(submitButtonValue));
httpPost.setEntity(entity);
HttpResponse postResponse = httpClient.execute(httpPost, httpContext);
// ...
Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • I tried this but in vain. i set up a similar dummy website. I am getting 200 OK response while i submit the post response for jsf page. For some reason it is not calling the submit method. I put a breakpoint for the submit method in server, but the call never reaches there. – Richie Dec 25 '11 at 10:07
  • It's hard to point out the real problem with the information given so far. Do you understand what you have to change in the code example in order to get it to work for the particular website? – BalusC Dec 25 '11 at 12:44
  • yup. I changed the URL and submit button value to match my webpage.I also changed the path of file to upload – Richie Dec 25 '11 at 13:29
  • I added one more part to entity "%formname%_SUBMIT" with string value 1 and it started to work. The other hidden parameter which was not set in multipart was this - tried my luck and voila! Thanks a ton mate, you really are a saver. ;) And JSoup is a cool api! – Richie Dec 25 '11 at 13:41
  • Oh, that must have been an old JSF 1.x webapp. Sorry, didn't thought of that. Glad you figured it. Yes indeed, Jsoup is very slick :) – BalusC Dec 25 '11 at 15:41
  • Is there any other way to make JSF Form submit without passing the viewStateID and JSessison id – user684434 Jan 31 '12 at 16:14
  • @user684434: No. JSF is a stateful MVC framework, not stateless. The answer would otherwise have been simpler. – BalusC Jan 31 '12 at 16:25
1

Try using HttpClient, here's an article that I think describes what you want, towards the bottom there's a section titled "Using HttpClient-Based FileUpload".

Hope this helps.

Tom
  • 39,281
  • 4
  • 35
  • 60
  • Thanks mate for the answer. I had tried this but since it was a jsf app, I had to set the hidden parameters as well as BalusC pointed out in his answer. – Richie Dec 25 '11 at 13:44
0

Probably that webpage just sends a POST request to the server with the contents of the form. You can easily send such a POST request yourself from Java, without using that page. For example this article shows an example of sending POST requests from Java

Robin
  • 34,480
  • 5
  • 43
  • 90
0

What you'll need to do is to examine the HTML on the page and work out what parameters are needed to post the form. It'll probably look something like this:

<form action="/RequestURL">
<input type=file name=file1>
<input type=textbox name=value1>
</form>

Based on that you can write some code to do a POST request to the url:

String data = URLEncoder.encode("value1", "UTF-8") + "=" + URLEncoder.encode("value1", "UTF-8");
data += "&" + URLEncoder.encode("file1", "UTF-8") + "=" + URLEncoder.encode(FileData, "UTF-8");

// Send data
URL url = new URL("http://servername.com/RequestURL");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
wr.close();

Remember that the person who wrote the page might do some checks to make sure the POST request came from the same site. In that case you might be in trouble, and you might need to set the user agent correctly.

Rocklan
  • 7,288
  • 2
  • 28
  • 46
0

You could try to use HtmlUnit for this. It provides a very simply API for simulating browser actions. I already used this approach for similar requirements. It's very easy. You should give it a try.

chkal
  • 5,532
  • 18
  • 26