package er.ajax;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOAssociation;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WODirectAction;
import com.webobjects.appserver.WOElement;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import er.extensions.appserver.ERXHttpStatusCodes;
import er.extensions.appserver.ERXResponse;
/**
* Simple component to ping the session in the background. It can do two things. The first is
* to execute JavaScript if the session is no longer valid. The default action is to close the window
* that the ping came from. The second thing it can do is to keep the session alive.
* This can be useful if you want the session to not time out on particular pages. It should be
* used with caution as it can prevent scheduled restarts if the user leaves the browser window open.
*
* @binding frequency the period between pings of the application (optional, default 60 seconds)
* @binding keepSessionAlive true if session should be checked out to reset timeout when the
* application is pinged (optional, default false)
* @binding parameters optional URL parameter string appended when application is pinged (optional, no default)
* @binding onFailure function to execute if the session has expired or other HTTP error code returned from
* ping (optional, default "function(response) { window.close();}")
* @binding asynchronous true if the ping should be made asynchronously (optional, default true)
* @binding evalScripts true if the ping results may contain JavaScript that should be evaluated (optional, default false)
* @binding method the HTTP request method to use for the ping (optional, default "get")
*
* @author chill
*/
public class AjaxSessionPing extends AjaxDynamicElement {
public AjaxSessionPing(String name, NSDictionary<String, WOAssociation> associations, WOElement children) {
super(name, associations, children);
}
/**
* Appends script to start Ajax.ActivePeriodicalUpdater to the response.
*/
@Override
public void appendToResponse(WOResponse response, WOContext context) {
super.appendToResponse(response, context);
WOComponent component = context.component();
response.appendContentString("<script>var AjaxSessionPinger = new Ajax.ActivePeriodicalUpdater('AjaxSessionPinger', '");
if (booleanValueForBinding("keepSessionAlive", false, component)) {
response.appendContentString(context.directActionURLForActionNamed("AjaxSessionPing$Action/pingSessionAndKeepAlive", null, context.secureMode(), false));
} else {
response.appendContentString(context.directActionURLForActionNamed("AjaxSessionPing$Action/pingSession", null, context.secureMode(), false));
}
response.appendContentString("', ");
AjaxOptions.appendToResponse(createAjaxOptions(component), response, context);
response.appendContentString(");</script>");
}
/**
* Gathers the bindings into an AjaxOptions dictionary.
*
* @param component the component to evaluate the bindings in
* @return the bindings in the form of an AjaxOptions dictionary
*/
public NSDictionary createAjaxOptions(WOComponent component) {
NSMutableArray<AjaxOption> ajaxOptionsArray = new NSMutableArray<>();
ajaxOptionsArray.addObject(new AjaxOption("asynchronous", Boolean.TRUE, AjaxOption.BOOLEAN));
ajaxOptionsArray.addObject(new AjaxOption("evalScripts", Boolean.FALSE, AjaxOption.BOOLEAN));
ajaxOptionsArray.addObject(new AjaxOption("frequency", Integer.valueOf(60), AjaxOption.NUMBER));
ajaxOptionsArray.addObject(new AjaxOption("method", "get", AjaxOption.STRING));
ajaxOptionsArray.addObject(new AjaxOption("onFailure", "function(response) { window.close();}", AjaxOption.SCRIPT));
ajaxOptionsArray.addObject(new AjaxOption("parameters", AjaxOption.STRING));
return AjaxOption.createAjaxOptionsDictionary(ajaxOptionsArray, component, associations());
}
/**
* Unused.
*/
@Override
public WOActionResults handleRequest(WORequest request, WOContext context) {
return null;
}
/**
* Uses Prototype and Wonder
*/
@Override
protected void addRequiredWebResources(WOResponse response, WOContext context) {
addScriptResourceInHead(context, response, "prototype.js");
addScriptResourceInHead(context, response, "wonder.js");
}
/**
* Internal WODirectAction subclass to handle the request from AjaxSessionPing.
*/
public static class Action extends WODirectAction {
public Action(WORequest request) {
super(request);
}
/**
* If there is a session, returns a response with a success (200) code. If there is
* not a session, returns a response with a failure (300) code so that the
* ActivePeriodicalUpdater can call the onFailure call back.
*
* @return bare HTTP response with status set
*/
public WOActionResults pingSessionAction() {
ERXResponse response = new ERXResponse();
if (existingSession() != null) {
session();
} else {
response.setStatus(ERXHttpStatusCodes.MULTIPLE_CHOICES); // CHECKME is that really the appropriate status code?
}
return response;
}
/**
* Same as pingSessionAction, but also checks out session to keep it alive.
*
* @see #pingSessionAction
* @return bare HTTP response with status set
*/
public WOActionResults pingSessionAndKeepAliveAction() {
if (existingSession() != null) {
session();
}
return pingSessionAction();
}
}
}