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 |