//
// ERXPathDirectActionRequestHandler.java
// ERExtensions
//
// Created by Max Muller on Thu May 08 2003.
//
package er.extensions.appserver;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver._private.WOURLEncoder;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
/**
* The path direct action request handler allows for storing information
* in the request path. For instance you could have the request path:
* /WebObjects/MyApp.woa/wpa/com.foo.SomeActionClass/bar/gee/wiz=neat/actionName
* This action is treated just like:
* /WebObjects/MyApp.woa/wpa/com.foo.SomeActionClass/actionName
*
*/
public class ERXPathDirectActionRequestHandler extends ERXDirectActionRequestHandler {
private static final Logger log = LoggerFactory.getLogger(ERXDirectActionRequestHandler.class);
/**
* Specifies if the request handler eats the action class from the URL
*/
private boolean useClassName = true;
/**
* Specifies if the request handler eats the action name from the URL
*/
private boolean useActionName = true;
/**
* Public constructor, just calls super
*/
public ERXPathDirectActionRequestHandler() {
super();
}
/**
* Public constructor, just calls super
*
* @param actionClassName
* action class name
* @param defaultActionName
* action name
* @param shouldAddToStatistics
* boolean to add to stats
*/
public ERXPathDirectActionRequestHandler(String actionClassName, String defaultActionName, boolean shouldAddToStatistics) {
super(actionClassName, defaultActionName, shouldAddToStatistics);
}
/**
* Creates the request handler and lets you specify if the URLs assume and action class in front and action name in back.
* This is useful when you have inner DA classes like SomeComponent$SomeAction and don't want this to appear in the URLs.
* @param actionClassName action class name
* @param defaultActionName default action name
* @param shouldAddToStatistics boolean if request should add to stats
* @param doUseClassName if false, do not assume action class name in URL
* @param doUseActionName if false, do not assume action name in URL
*/
public ERXPathDirectActionRequestHandler(String actionClassName, String defaultActionName, boolean shouldAddToStatistics, boolean doUseClassName, boolean doUseActionName) {
this(actionClassName, defaultActionName, shouldAddToStatistics);
useClassName = doUseClassName;
useActionName = doUseActionName;
}
/**
* Modified version for getting the request handler path for a given
* request.
*
* @param aRequest
* a given request
* @return array of request handler paths for a given request, truncates to
* the first and last component if the number of components is
* greater than 2, and tries to divine the meaning of paths when there
* are only one or 2 path components.
*/
@Override
public NSArray getRequestHandlerPathForRequest(WORequest aRequest) {
NSArray paths = super.getRequestHandlerPathForRequest(aRequest);
NSMutableArray temp = new NSMutableArray();
if (paths != null) {
int pathCount = paths.count();
String firstPathComponent = pathCount > 0 ? (String)paths.objectAtIndex(0) : null;
String lastPathComponent = (String)paths.lastObject();
if (pathCount > 2) {
if (useClassName && useActionName) {
temp.addObject(firstPathComponent);
temp.addObject(lastPathComponent);
} else {
if (!useClassName) {
temp.addObject(lastPathComponent);
} else {
temp.addObject(firstPathComponent);
}
}
} else if (pathCount == 2) {
if (useClassName) {
temp.addObject(firstPathComponent);
}
if (useActionName) {
temp.addObject(lastPathComponent);
}
} else if (pathCount == 1) {
// If there's just 1 path component it can either be an action name or the name of the action class.
if ((useActionName && !lastPathComponent.equals(defaultActionName)) ||
(useClassName && !lastPathComponent.equals(actionClassName))) {
temp.addObject(lastPathComponent);
}
}
}
if (actionClassName != null && temp.count() == 0) {
temp.addObject(actionClassName);
}
return temp.immutableClone();
}
/**
* Returns a dictionary similar to the normal request form value dict.
* Translates /cgi-bin/.../wpa/foo/bar=2/baz into {foo = foo; bar = 2;
* baz = baz}
*
* @param request request to parse
* @param useActionClass true if first item should get ignored
* @param useActionName true if last item should get ignored
* @return the dictionary of form values
*/
public static NSDictionary<String, String> formValuesFromRequest(WORequest request, boolean useActionClass, boolean useActionName) {
NSMutableDictionary<String, String> params = new NSMutableDictionary<>();
boolean foundRequestHandler = false;
for (Enumeration<String> e = NSArray.componentsSeparatedByString(request.uri(), "/").objectEnumerator(); e.hasMoreElements();) {
String part = e.nextElement();
try {
part = URLDecoder.decode(part, WOURLEncoder.WO_URL_ENCODING);
}
catch (UnsupportedEncodingException ex) {
log.error("Encoding not found: " + WOURLEncoder.WO_URL_ENCODING, ex);
}
if (foundRequestHandler && (!useActionName || (useActionName && e.hasMoreElements()))) {
String[] pair = part.split("=", 2);
String key = pair[0];
String value = (pair.length == 2 ? pair[1] : pair[0]);
if (pair.length == 2) {
params.setObjectForKey(pair[1], pair[0]);
}
else {
params.setObjectForKey(pair[0], pair[0]);
}
}
if (part.equals(request.requestHandlerKey())) {
foundRequestHandler = true;
if (useActionClass && e.hasMoreElements()) {
part = e.nextElement();
}
}
}
return params;
}
}