I have very simple JSF bean like shown below:
import org.jboss.seam.annotations.Name;
@Name(Sample.NAME)
public class Sample {
public static final String NAME="df";
private String text = "text-test";
public void sampleM(){
System.out.println("Test: "+text);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
And JSF form connected with this component:
<h:form id="sampleForm">
<h:commandButton id="sampleButton" action="#{df.sampleM()}" value="ok" />
</h:form>
Now, I would like to programmatically send POST request to this form.
According to my investigation the key here are POST parameters. Selected properly gives proper results (String 'Test: text-test' is printed on serwer's console).
So the question is: How should I select POST data that was correct?
JSF form shown above produces this HTML form:
<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="sampleForm" value="sampleForm" />
<input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>
So these parameters are corrent.
But how can I find out what parameters (name and value) will be sufficient for any other component?
For example: when I send POST data the same like in shown HTML form but with different 'javax.faces.ViewState' parameter value, component method will not be executed.
I understand that you're basically asking how to submit a JSF form programmatically using some HTTP client such as java.net.URLConnection
or Apache HttpComponents Client, right?
You need to send a GET request first and make sure that you maintain the same HTTP session (basically, the JSESSIONID
cookie) across requests. Let your HTTP client extract the Set-Cookie
header from the response of the first GET request, obtain the JSESSIONID
cookie from it and send it back as Cookie
header of subsequent POST requests. This will maintain the HTTP session in the server side, otherwise JSF will treat it as a "View Expired" which may return either on a decently configured JSF web application a HTTP 500 error page with ViewExpiredException
, or on a badly configured JSF web application behave as a page refresh.
As part of JSF's stateful nature and implied CSRF attack prevention, the forms must be submitted with a valid javax.faces.ViewState
value as the client has retrieved itself on the initial GET request. You also need to make sure that you send the name=value
pair of all other hidden fields and particularly the one of the submit button along as well.
So, if your initial GET request gives you this HTML back
<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="sampleForm" value="sampleForm" />
<input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>
then you need to parse it (Jsoup may be helpful in this) and extract the following request parameters:
sampleForm=sampleForm
sampleForm:sampleButton=ok
javax.faces.ViewState=j_id65
Finally send a POST request on /pages/main/main.smnet
with exactly those request parameters (and the JSESSIONID
cookie!). Be careful though, it's possible that a (poor) JSF developer has skipped e.g. id="sampleButton"
from the <h:commandButton>
and then JSF would autogenerate one which looks like in this format sampleForm:j_id42
. You can't hardcode them as the value may change depending on the component's position in the server side tree and you would then really need to parse it out the obtained HTML.
Nonetheless, it's wise to contact the site owner/admin and ask if there isn't a web service API available for the task you had in mind. A decent Java EE website which uses a JSF application for a HTML frontend usually also uses a separate JAX-RS application for a REST frontend. It is much more easy and reliable to extract information via such a web service API than by scraping a HTML document.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With