| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| WODirectAction |
|
| 2.9166666666666665;2.917 |
| 1 | /* |
|
| 2 | Wotonomy: OpenStep design patterns for pure Java applications. |
|
| 3 | Copyright (C) 2000 Blacksmith, Inc. |
|
| 4 | ||
| 5 | This library is free software; you can redistribute it and/or |
|
| 6 | modify it under the terms of the GNU Lesser General Public |
|
| 7 | License as published by the Free Software Foundation; either |
|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|
| 9 | ||
| 10 | This library is distributed in the hope that it will be useful, |
|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 13 | Lesser General Public License for more details. |
|
| 14 | ||
| 15 | You should have received a copy of the GNU Lesser General Public |
|
| 16 | License along with this library; if not, see http://www.gnu.org |
|
| 17 | */ |
|
| 18 | ||
| 19 | package net.wotonomy.web; |
|
| 20 | ||
| 21 | import java.lang.reflect.InvocationTargetException; |
|
| 22 | import java.lang.reflect.Method; |
|
| 23 | ||
| 24 | import javax.servlet.http.HttpSession; |
|
| 25 | ||
| 26 | import net.wotonomy.foundation.NSArray; |
|
| 27 | import net.wotonomy.foundation.NSSelector; |
|
| 28 | import net.wotonomy.foundation.internal.Introspector; |
|
| 29 | import net.wotonomy.foundation.internal.ValueConverter; |
|
| 30 | ||
| 31 | /** |
|
| 32 | * A pure java implementation of WODirectAction. |
|
| 33 | * This class provides a number of services to subclasses, |
|
| 34 | * including access to the query parameters, the request, |
|
| 35 | * the session, and logging and debugging facilities. |
|
| 36 | * A new instance of the class is created and then destroyed |
|
| 37 | * for every request-response cycle.<br><br> |
|
| 38 | * |
|
| 39 | * Subclass this to implement direct actions for your |
|
| 40 | * application. Subclasses would typically override the |
|
| 41 | * constructor to initialize state based on the request, |
|
| 42 | * and then provide additional methods that would be invoked |
|
| 43 | * based on the value at the end of the URI. <br><br> |
|
| 44 | * |
|
| 45 | * Example: "http://www/MyApp.woa/MyActions/search" would call |
|
| 46 | * the method named "searchAction" on the DirectAction subclass |
|
| 47 | * named "MyActions". If the subclass name is omitted, a subclass |
|
| 48 | * named "DirectAction" is assumed to exist within the application. |
|
| 49 | * |
|
| 50 | * @author michael@mpowers.net |
|
| 51 | * @author $Author: cgruber $ |
|
| 52 | * @version $Revision: 905 $ |
|
| 53 | */ |
|
| 54 | public class WODirectAction |
|
| 55 | { |
|
| 56 | private WORequest request; |
|
| 57 | WOContext context; |
|
| 58 | ||
| 59 | /** |
|
| 60 | * Default constructor. This is called implicitly by |
|
| 61 | * subclasses in all cases. Package access only. |
|
| 62 | */ |
|
| 63 | 0 | WODirectAction () |
| 64 | 0 | { |
| 65 | ||
| 66 | 0 | } |
| 67 | ||
| 68 | /** |
|
| 69 | * Request constructor. This is the constructor used |
|
| 70 | * to create an action in response to a user request. |
|
| 71 | * Override to perform any necessary initialization in |
|
| 72 | * your subclass. |
|
| 73 | */ |
|
| 74 | public WODirectAction (WORequest aRequest) |
|
| 75 | { |
|
| 76 | 0 | this(); |
| 77 | 0 | request = aRequest; |
| 78 | 0 | } |
| 79 | ||
| 80 | /** |
|
| 81 | * Returns the response from the component named "Main". |
|
| 82 | */ |
|
| 83 | public WOActionResults defaultAction() |
|
| 84 | { |
|
| 85 | 0 | return pageWithName("Main").generateResponse(); |
| 86 | } |
|
| 87 | ||
| 88 | /** |
|
| 89 | * Returns the WORequest object for the current request. |
|
| 90 | */ |
|
| 91 | public WORequest request () |
|
| 92 | { |
|
| 93 | 0 | return request; |
| 94 | } |
|
| 95 | ||
| 96 | /** |
|
| 97 | * Returns the existing session, or null if no session exists. |
|
| 98 | */ |
|
| 99 | public WOSession existingSession () |
|
| 100 | { |
|
| 101 | //FIXME: this is incorrect |
|
| 102 | 0 | HttpSession session = request.servletRequest().getSession(); |
| 103 | 0 | if ( session == null ) return null; |
| 104 | 0 | WOSession wosession = new WOSession(); |
| 105 | 0 | wosession.setServletSession( session ); |
| 106 | 0 | return wosession; |
| 107 | } |
|
| 108 | ||
| 109 | /** |
|
| 110 | * Returns the existing session if it exists. If no session |
|
| 111 | * exists, returns a newly created session. Note that if the |
|
| 112 | * user client does not support session ids/cookies, this will |
|
| 113 | * create a new session with each request. |
|
| 114 | */ |
|
| 115 | public WOSession session () |
|
| 116 | { |
|
| 117 | //FIXME: this is incorrect |
|
| 118 | 0 | WOSession wosession = new WOSession(); |
| 119 | 0 | wosession.setServletSession( |
| 120 | 0 | request.servletRequest().getSession( true ) ); |
| 121 | 0 | return wosession; |
| 122 | } |
|
| 123 | ||
| 124 | /** |
|
| 125 | * Returns the named WOComponent. |
|
| 126 | */ |
|
| 127 | public WOComponent pageWithName (String aString) |
|
| 128 | { |
|
| 129 | 0 | return request.application().pageWithName( aString, context ); |
| 130 | } |
|
| 131 | ||
| 132 | /** |
|
| 133 | * Appends "Action" to the specified string and tries to invoke |
|
| 134 | * method with that name and no arguments. Returns null if |
|
| 135 | * the method does not exist. If anAction is null, "defaultAction" |
|
| 136 | * will be assumed. |
|
| 137 | */ |
|
| 138 | public WOActionResults performActionNamed (String anAction) |
|
| 139 | { |
|
| 140 | 0 | if ( anAction == null ) anAction = "default"; |
| 141 | try |
|
| 142 | { |
|
| 143 | 0 | NSSelector sel = new NSSelector( anAction+"Action" ); |
| 144 | 0 | return (WOActionResults) sel.invoke( this ); |
| 145 | } |
|
| 146 | 0 | catch ( NoSuchMethodException exc ) |
| 147 | { |
|
| 148 | // returns below |
|
| 149 | } |
|
| 150 | 0 | catch ( InvocationTargetException exc ) |
| 151 | { |
|
| 152 | 0 | Throwable e = exc.getTargetException(); |
| 153 | 0 | exc.printStackTrace(); |
| 154 | 0 | throw new RuntimeException( e.toString() ); |
| 155 | } |
|
| 156 | 0 | catch ( Exception exc ) |
| 157 | { |
|
| 158 | 0 | exc.printStackTrace(); |
| 159 | 0 | throw new RuntimeException( exc.toString() ); |
| 160 | 0 | } |
| 161 | 0 | WOResponse error = new WOResponse(); |
| 162 | 0 | error.setStatus( 404 ); // not found |
| 163 | 0 | error.appendContentString( |
| 164 | 0 | "Could not find method named \"" + anAction + "Action\"." ); |
| 165 | 0 | return error; |
| 166 | } |
|
| 167 | ||
| 168 | /** |
|
| 169 | * Assigns the arrays of form values for the specified keys |
|
| 170 | * to properties on this object with matching names whose type |
|
| 171 | * is NSArray or is convertable from a Collection. |
|
| 172 | */ |
|
| 173 | public void takeFormValueArraysForKeyArray (NSArray anArray) |
|
| 174 | { |
|
| 175 | 0 | if ( anArray == null ) return; |
| 176 | ||
| 177 | Method m; |
|
| 178 | Object key; |
|
| 179 | Object value; |
|
| 180 | 0 | java.util.Enumeration e = anArray.objectEnumerator(); |
| 181 | 0 | while ( e.hasMoreElements() ) |
| 182 | { |
|
| 183 | 0 | key = e.nextElement(); |
| 184 | 0 | value = request.formValuesForKey( key.toString() ); |
| 185 | try |
|
| 186 | { |
|
| 187 | // obtain setter method for this class |
|
| 188 | 0 | m = Introspector.getPropertyWriteMethod( |
| 189 | 0 | this.getClass(), key.toString(), |
| 190 | 0 | new Class[] { Introspector.WILD } ); |
| 191 | 0 | if ( m != null ) |
| 192 | { |
|
| 193 | // if value isn't null, try to convert it to type |
|
| 194 | 0 | if ( value != null ) |
| 195 | { |
|
| 196 | 0 | Class[] paramTypes = m.getParameterTypes(); |
| 197 | 0 | if ( ! paramTypes[0].isAssignableFrom( |
| 198 | 0 | value.getClass() ) ) |
| 199 | { |
|
| 200 | //TODO: find a constructor whose parameter |
|
| 201 | // is assignable from value.getClass() |
|
| 202 | // and instantiate it in the place of value. |
|
| 203 | } |
|
| 204 | } |
|
| 205 | // set property to value |
|
| 206 | 0 | m.invoke( this, new Object[] { value } ); |
| 207 | } |
|
| 208 | } |
|
| 209 | 0 | catch ( Exception exc ) |
| 210 | { |
|
| 211 | // show error and continue |
|
| 212 | 0 | debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc ); |
| 213 | 0 | } |
| 214 | 0 | } |
| 215 | ||
| 216 | 0 | } |
| 217 | ||
| 218 | /** |
|
| 219 | * Assigns the form values for the specified keys to properties |
|
| 220 | * on this object with matching names. |
|
| 221 | */ |
|
| 222 | public void takeFormValuesForKeyArray (NSArray anArray) |
|
| 223 | { |
|
| 224 | 0 | if ( anArray == null ) return; |
| 225 | ||
| 226 | Method m; |
|
| 227 | Object key; |
|
| 228 | Object value; |
|
| 229 | 0 | java.util.Enumeration e = anArray.objectEnumerator(); |
| 230 | 0 | while ( e.hasMoreElements() ) |
| 231 | { |
|
| 232 | 0 | key = e.nextElement(); |
| 233 | 0 | value = request.formValueForKey( key.toString() ); |
| 234 | try |
|
| 235 | { |
|
| 236 | // obtain setter method for this class |
|
| 237 | 0 | m = Introspector.getPropertyWriteMethod( |
| 238 | 0 | this.getClass(), key.toString(), |
| 239 | 0 | new Class[] { Introspector.WILD } ); |
| 240 | 0 | if ( m != null ) |
| 241 | { |
|
| 242 | // if value isn't null, try to convert it to type |
|
| 243 | 0 | if ( value != null ) |
| 244 | { |
|
| 245 | 0 | Class[] paramTypes = m.getParameterTypes(); |
| 246 | 0 | Object convertedValue = |
| 247 | 0 | ValueConverter.convertObjectToClass( |
| 248 | 0 | value, paramTypes[0] ); |
| 249 | 0 | if ( convertedValue != null ) |
| 250 | { |
|
| 251 | 0 | value = convertedValue; |
| 252 | } |
|
| 253 | } |
|
| 254 | // set property to value |
|
| 255 | 0 | m.invoke( this, new Object[] { value } ); |
| 256 | } |
|
| 257 | } |
|
| 258 | 0 | catch ( Exception exc ) |
| 259 | { |
|
| 260 | // show error and continue |
|
| 261 | 0 | debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc ); |
| 262 | 0 | } |
| 263 | 0 | } |
| 264 | ||
| 265 | 0 | } |
| 266 | ||
| 267 | /** |
|
| 268 | * Writes a message to the standard error stream. |
|
| 269 | */ |
|
| 270 | public static void logString (String aString) |
|
| 271 | { |
|
| 272 | 0 | System.err.println( aString ); |
| 273 | 0 | } |
| 274 | ||
| 275 | /** |
|
| 276 | * Writes a message to the standard error stream |
|
| 277 | * if debugging is activated. |
|
| 278 | */ |
|
| 279 | public static void debugString (String aString) |
|
| 280 | { |
|
| 281 | // TODO: Check to see if debugging is enabled. |
|
| 282 | 0 | System.err.println( aString ); |
| 283 | 0 | } |
| 284 | } |
|
| 285 | ||
| 286 | /* |
|
| 287 | * $Log$ |
|
| 288 | * Revision 1.2 2006/02/19 01:44:02 cgruber |
|
| 289 | * Add xmlrpc files |
|
| 290 | * Remove jclark and replace with dom4j and javax.xml.sax stuff |
|
| 291 | * Re-work dependencies and imports so it all compiles. |
|
| 292 | * |
|
| 293 | * Revision 1.1 2006/02/16 13:22:22 cgruber |
|
| 294 | * Check in all sources in eclipse-friendly maven-enabled packages. |
|
| 295 | * |
|
| 296 | * Revision 1.5 2003/01/13 22:24:51 mpowers |
|
| 297 | * Request-response cycle is working with session and page persistence. |
|
| 298 | * |
|
| 299 | * Revision 1.4 2003/01/09 21:16:48 mpowers |
|
| 300 | * Bringing request-response cycle more into conformance. |
|
| 301 | * |
|
| 302 | * Revision 1.3 2003/01/07 15:58:11 mpowers |
|
| 303 | * Implementing the request-response cycle. |
|
| 304 | * WOSession refactored to support distribution. |
|
| 305 | * |
|
| 306 | * Revision 1.2 2002/12/17 14:57:43 mpowers |
|
| 307 | * Minor corrections to WORequests's parsing, and updated javadocs. |
|
| 308 | * |
|
| 309 | * Revision 1.1.1.1 2000/12/21 15:53:18 mpowers |
|
| 310 | * Contributing wotonomy. |
|
| 311 | * |
|
| 312 | * Revision 1.2 2000/12/20 16:25:50 michael |
|
| 313 | * Added log to all files. |
|
| 314 | * |
|
| 315 | * |
|
| 316 | */ |
|
| 317 |