[Opensource] Added transaction token support in expresso... how to use it
Raul DAVIDOVICH
R.DAVIDOVICH at caconcology.com
Thu Oct 17 08:27:26 PDT 2002
Hi all,
I sent an email with the sources for transaction token support in
expresso, but I didn't say what it is or how is it used.. not very clever
from my side..
maybe this could go to EDG too?
Transaction tokens
What are them?
They are one-time use tokens, used to avoid duplicate submissions of
information (typical case in a web app: user clicks "submit", then clicks
"back" and then "submit" again)
How they work?
in struts, the generateToken() method generates a key with the session id
and the current time. This string is saved in the HttpSession, and included
as a hidden field in the form.
At the form validation, the validity of the token is verified. When the
transaction succeeds, the string is removed from the session.
How is it used in expresso?
There are four methods for managing these tokens:
saveToken(ControllerRequest)
isTokenValid(ControllerRequest)
resetToken(ControllerRequest)
generateToken(ControllerRequest)
in the controller, when generating the form, you call
"saveToken(myRequest);", and IT GENERATES AND SAVES the token into the
HttpSession
In the next state, when dealing with the form fields, you call
"isTokenValid(myRequest);" which returns true or false.
Finnally, when the token isn't needed any more (typically when the
transaction is succeeded) you call "resetToken(myRequest);"
For all this to work, you MUST use the struts <html:form> tag or the
expresso-html <html:form> tag. This is very important, because this tag
checks the session for a token, and it sets it up automatically as a hidden
field with the correct name; otherwise, you should manually add a hidden
field with the name "org.apache.struts.taglib.html.Constants.TOKEN_KEY".
You can also do manually all the token handling. the generateToken() method
is useful there..
Here are some code examples:
a) Struts style
public class MyController extends DBController{
private String thisClass = MyController .class.getName();
public MyController () {
super();
/* List State */
State list = new State("listDB", "List myDBObjects State");
addState(list);
setInitialState("listState");
/* Prompt State */
State prompt = new State("promptDb", "Prompt for data State");
addState(prompt);
/* Treatment State */
State treatment = new State("treatDb", "Deal with data State");
addState(treatment);
setSchema("com.mycompany.MySchema");
}/*MyController*/
...
/**
* Prompt State
*/
protected ControllerResponse runPromptState(ControllerRequest params,
ControllerResponse response) throws ControllerException{
Input code = new Input();
code.setName("DbCode");
code.setLabel("Code");
code.setDisplayLength(3);
code.setMaxLength(3);
code.setType("text");
code.setDefaultValue(db.getField("DbCode"));
response.add(code);
Input label = new Input();
label.setName("DbLabel");
label.setLabel("DB Label");
label.setDisplayLength(20);
label.setMaxLength(40);
label.setType("text");
label.setDefaultValue(da.getField("DbLabel"));
response.add(label);
Transition treatTransition = new Transition("Treat", getClass
().getName());
treatTransition.setName("TreatDb");
treatTransition.setLabel("Save");
treatTransition.addParam("state", "treatment");
treatTransition.addParam("next", params.getParameter("next"));
response.add(treatTransition);
saveToken(params);
response.setStyle("promptEditDb"); //the JSP page set up in
struts-config.xml which shows the form
return response;
}/*runPromptState*/
/**
* Treat Information State
*/
protected ControllerResponse runTreatmentState(ControllerRequest
params, ControllerResponse response) throws ControllerException{
String codeStr = params.getParameter("DbCode");
String labelStr = params.getParameter("DbLabel");
ErrorCollection errors = new ErrorCollection();
try{
MyDBObject db = new MyDBObject();
db.setDBName(params.getDBName());
// verify the token for avoiding duplicate submissions
if(!isTokenValid(params)){
errors.addError("The form has already been submited");
}
//validate null fields and correct types
params.validateDBObject(db, errors);
if(errors.getErrorCount()!=0){
response.saveErrors(errors);
try{
transition("prompt", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
else{
db.setField("DbCode", codeStr );
db.setField("DbLabel", labelStr);
db.add();
resetToken(params);
try{
transition("list", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
}
catch (DBException dbe){
errors.addError("unable to create MyDBObject: '" + labelStr + "'.
Please verify all of the fields" );
response.saveErrors(errors);
try{
transition("prompt", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
response.saveErrors(errors);
return response;
}/*runCreateDAParState*/
}/* MyController */
b) Manual token handling
NOTE: If you do this, you CANNOT use struts <html:form> tag (or
expresso-html <html:form> tag), because they don't know how to deal with
SerializedString
public class MyController extends DBController{
private String thisClass = MyController .class.getName();
public MyController () {
super();
/* List State */
State list = new State("listDB", "List myDBObjects State");
addState(list);
setInitialState("listState");
/* Prompt State */
State prompt = new State("promptDb", "Prompt for data State");
addState(prompt);
/* Treatment State */
State treatment = new State("treatDb", "Deal with data State");
addState(treatment);
setSchema("com.mycompany.MySchema");
}/*MyController*/
...
/**
* Prompt State
*/
protected ControllerResponse runPromptState(ControllerRequest params,
ControllerResponse response) throws ControllerException{
Input code = new Input();
code.setName("DbCode");
code.setLabel("Code");
code.setDisplayLength(3);
code.setMaxLength(3);
code.setType("text");
code.setDefaultValue(db.getField("DbCode"));
response.add(code);
Input label = new Input();
label.setName("DbLabel");
label.setLabel("DB Label");
label.setDisplayLength(20);
label.setMaxLength(40);
label.setType("text");
label.setDefaultValue(da.getField("DbLabel"));
response.add(label);
Transition treatTransition = new Transition("Treat", getClass
().getName());
treatTransition.setName("TreatDb");
treatTransition.setLabel("Save");
treatTransition.addParam("state", "treatment");
treatTransition.addParam("next", params.getParameter("next"));
response.add(treatTransition);
String myToken = generateToken(params);
Input token = new Input();
token.setName("token_name");
token.setType("hidden");
token.setDefaultValue(myToken);
response.add(token);
Persistent session mySession = params.getSession();
mySession.setPersistentAttribute("token_name", myToken);
response.setStyle("promptEditDb"); //the JSP page set up in
struts-config.xml which shows the form
return response;
}/*runPromptState*/
/**
* Treat Information State
*/
protected ControllerResponse runTreatmentState(ControllerRequest
params, ControllerResponse response) throws ControllerException{
String codeStr = params.getParameter("DbCode");
String labelStr = params.getParameter("DbLabel");
String myToken = params.getParameter("token_name");
ErrorCollection errors = new ErrorCollection();
PersistentSession mySession = params.getSession();
String sessionToken = mySession.getPersistentAttribute
("token_name").toString();
try{
MyDBObject db = new MyDBObject();
db.setDBName(params.getDBName());
// verify the token for avoiding duplicate submissions
if(sessionToken == null || myToken == null ||
!sessionToken.equals(myToken)){ //or any other token validation you want to
do
errors.addError("The form has already been submited");
}
//validate null fields and correct types
params.validateDBObject(db, errors);
if(errors.getErrorCount()!=0){
response.saveErrors(errors);
try{
transition("prompt", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
else{
db.setField("DbCode", codeStr );
db.setField("DbLabel", labelStr);
db.add();
mySession.removePersistentAttribute("token_name");
try{
transition("list", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
}
catch (DBException dbe){
errors.addError("unable to create MyDBObject: '" + labelStr + "'.
Please verify all of the fields" );
response.saveErrors(errors);
try{
transition("prompt", params, response);
}
catch (NonHandleableException nhe) {
errors.addError("problem after transition");
}
}
response.saveErrors(errors);
return response;
}/*runCreateDAParState*/
}/* MyController */
---------------------------------------------------
Raul Davidovich
Responsable Informatique
Cvitkovic & Associés Consultants
(33) 1 45 15 40 68
(33) 1 45 15 40 41 Fax
-------------------------------------------------------
http://www.caconcology.com
More information about the Opensource
mailing list