// // ERXPathDirectAction.java // ERExtensions // // Created by Max Muller III on Fri Sep 19 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.WODirectAction; 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; import com.webobjects.foundation.NSRange; /** * Utility direct action class that provides a bunch of nice utility methods * if the direct action is accessed via a path direct action. See * {@link ERXPathDirectActionRequestHandler ERXPathDirectActionRequestHandler} * for more information. */ public class ERXPathDirectAction extends WODirectAction { // =========================================================================== // Class Constant(s) // --------------------------------------------------------------------------- private static final Logger log = LoggerFactory.getLogger(ERXPathDirectAction.class); // =========================================================================== // Instance Variable(s) // --------------------------------------------------------------------------- /** caches the path parts */ protected NSArray pathParts; /** caches the path parts by keys */ protected NSDictionary pathPartsByKeys; /** caches the path parts by case insensitive keys */ protected NSDictionary pathPartsByKeysCaseInsensitive; // =========================================================================== // Instance Constructor(s) // --------------------------------------------------------------------------- /** * Just calls super. */ public ERXPathDirectAction(WORequest aRequest) { super(aRequest); } // =========================================================================== // Instance Method(s) // --------------------------------------------------------------------------- /** * The path parts of a request correspond to to all of the pieces between the * request handler key and the class name. For instance given the direct action * path /WebObjects/MyApp.woa/wpa/foo/bar/MyDirectActionClass/action would * produce the path parts (foo, bar). * @return array of path parts for the given request */ public NSArray pathParts() { if (pathParts == null) { if (request().requestHandlerPathArray().count() > 2) { pathParts = request().requestHandlerPathArray().subarrayWithRange(new NSRange(1, request().requestHandlerPathArray().count() - 2)); } if (pathParts == null) { pathParts = NSArray.EmptyArray; } else { // Need to correctly WOUrlDecode the path parts NSMutableArray temp = new NSMutableArray(pathParts.count()); for (Enumeration pathPartEnumerator = pathParts.objectEnumerator(); pathPartEnumerator.hasMoreElements();) { try { temp.addObject(URLDecoder.decode((String)pathPartEnumerator.nextElement(), WOURLEncoder.WO_URL_ENCODING)); } catch (UnsupportedEncodingException e) { log.error("Encoding not found: {}", WOURLEncoder.WO_URL_ENCODING, e); } } pathParts = temp; } if (log.isDebugEnabled()) log.debug("Generated path parts: {} for uri: {}", pathParts, request().uri()); } return pathParts; } /** * Given an array of path parts (foo=food, bar=baz, gee) this will * produce a dictionary of the form: { foo=food; bar=baz; }. In the current * for this method does not handle multiple keys with the same name. * @return path parts broken down by key */ public NSDictionary pathPartsByKeys() { if (pathPartsByKeys == null) { NSMutableDictionary temp = null; NSMutableDictionary tempCaseInsensitive = null; for (Enumeration pathEnumerator = pathParts().objectEnumerator(); pathEnumerator.hasMoreElements();) { String path = (String)pathEnumerator.nextElement(); if (path.indexOf('=') != -1) { if (temp == null) { temp = new NSMutableDictionary(); tempCaseInsensitive = new NSMutableDictionary(); } NSArray parts = NSArray.componentsSeparatedByString(path, "="); if (parts.count() == 2) { temp.setObjectForKey(parts.objectAtIndex(1), parts.objectAtIndex(0)); tempCaseInsensitive.setObjectForKey(parts.objectAtIndex(1), ((String)parts.objectAtIndex(0)).toLowerCase()); } } } pathPartsByKeys = temp != null ? temp : NSDictionary.EmptyDictionary; pathPartsByKeysCaseInsensitive = tempCaseInsensitive != null ? tempCaseInsensitive : NSDictionary.EmptyDictionary; } return pathPartsByKeys; } /** * Same method as pathPartsByKeys except all of the keys have been down cased, ie * for path parts (Foo=food, bAr=baz, gee) this will give a dictionary of the form * { foo=food; bar=baz; }. * @return path parts by case insensitive key */ public NSDictionary pathPartsByKeysCaseInsensitive() { if (pathPartsByKeysCaseInsensitive == null) pathPartsByKeys(); return pathPartsByKeysCaseInsensitive; } /** * Determines if a path part exists for a given key. * @param key path part key * @return if a path was specified */ public boolean hasPathPartForKey(String key) { return hasPathPartForKey(key, false); } /** * Determines if a path part exists for a given key * with the option of performing a case insensitve * comparison. * @param key path part key * @param caseInsensitive key comparison should be case sensitive * @return if a path was specified */ public boolean hasPathPartForKey(String key, boolean caseInsensitive) { if (caseInsensitive) { key = key.toLowerCase(); } return caseInsensitive ? pathPartsByKeysCaseInsensitive().objectForKey(key) != null : pathPartsByKeys().objectForKey(key) != null; } /** * Gets a path part for a given key. * @param key path part key * @return path part for the key */ public String pathPartForKey(String key) { return pathPartForKeyWithDefault(key, null); } /** * Gets a path part for a given key, returning the default * value if nothing was specified. * @param key path part key * @param defaultValue default value * @return path part for the key or the default value */ public String pathPartForKeyWithDefault(String key, String defaultValue) { return pathPartForKeyWithDefault(key, defaultValue, false); } /** * Gets a path part for a given key, returning the default * value if nothing was specified. Adds the option for a * case insensitive comparison. * @param key path part key * @param defaultValue default value * @param caseInsensitiveCompare key comparison should ignore case * @return path part for the key or the default value */ public String pathPartForKeyWithDefault(String key, String defaultValue, boolean caseInsensitiveCompare) { String value = null; if (caseInsensitiveCompare) { key = key.toLowerCase(); value = (String)pathPartsByKeysCaseInsensitive().objectForKey(key); } else { value = (String)pathPartsByKeys().objectForKey(key); } return value != null ? value : defaultValue; } }