View Javadoc

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      WODirectAction ()
64      {
65      	
66      }
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      	this();
77  	    request = aRequest;
78      }
79  
80      /***
81      * Returns the response from the component named "Main".
82      */
83      public WOActionResults defaultAction()
84      {
85          return pageWithName("Main").generateResponse();   
86      }
87      
88  	/***
89  	* Returns the WORequest object for the current request.
90  	*/
91      public WORequest request ()
92      {
93      	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     	HttpSession session = request.servletRequest().getSession();
103 	    if ( session == null ) return null;
104 	    WOSession wosession = new WOSession();
105 	    wosession.setServletSession( session );
106 	    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 	    WOSession wosession = new WOSession();
119 	    wosession.setServletSession( 
120 	    	request.servletRequest().getSession( true ) );
121 	    return wosession;
122     }
123 
124 	/***
125 	* Returns the named WOComponent. 
126 	*/
127     public WOComponent pageWithName (String aString)
128     {
129     	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     	if ( anAction == null ) anAction = "default";
141 	    try 
142 	    {
143 		    NSSelector sel = new NSSelector( anAction+"Action" );
144 	    	return (WOActionResults) sel.invoke( this );
145 		}
146 		catch ( NoSuchMethodException exc )
147 		{
148 			// returns below
149 		}
150 		catch ( InvocationTargetException exc )
151 		{
152 			Throwable e = exc.getTargetException();
153             exc.printStackTrace();
154 			throw new RuntimeException( e.toString() );
155 		}
156 		catch ( Exception exc )
157 		{
158             exc.printStackTrace();
159 			throw new RuntimeException( exc.toString() );
160 		}
161         WOResponse error = new WOResponse();
162         error.setStatus( 404 ); // not found
163         error.appendContentString(
164             "Could not find method named \"" + anAction + "Action\"." );
165         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     	if ( anArray == null ) return;
176 	    
177     	Method m;
178 	    Object key;
179 	    Object value;
180 	    java.util.Enumeration e = anArray.objectEnumerator();
181 	    while ( e.hasMoreElements() )
182 	    {
183 	    	key = e.nextElement();
184 			value = request.formValuesForKey( key.toString() );
185 			try
186 			{
187                 // obtain setter method for this class
188                 m = Introspector.getPropertyWriteMethod(
189                         this.getClass(), key.toString(),
190                         new Class[] { Introspector.WILD } );
191                 if ( m != null )
192                 {
193                     // if value isn't null, try to convert it to type
194                     if ( value != null )
195                     {
196                         Class[] paramTypes = m.getParameterTypes();
197                     	if ( ! paramTypes[0].isAssignableFrom( 
198 			    			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                     m.invoke( this, new Object[] { value } );
207                 }
208 	    	}
209 		    catch ( Exception exc )
210 		    {
211 		    	// show error and continue
212 		    	debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
213 		    }
214 		}
215 	    	
216     }
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     	if ( anArray == null ) return;
225 	    
226     	Method m;
227 	    Object key;
228 	    Object value;
229 	    java.util.Enumeration e = anArray.objectEnumerator();
230 	    while ( e.hasMoreElements() )
231 	    {
232 	    	key = e.nextElement();
233 			value = request.formValueForKey( key.toString() );
234 			try
235 			{
236                 // obtain setter method for this class
237                 m = Introspector.getPropertyWriteMethod(
238                         this.getClass(), key.toString(),
239                         new Class[] { Introspector.WILD } );
240                 if ( m != null )
241                 {
242                     // if value isn't null, try to convert it to type
243                     if ( value != null )
244                     {
245                         Class[] paramTypes = m.getParameterTypes();
246                         Object convertedValue =
247                             ValueConverter.convertObjectToClass(
248                                 value, paramTypes[0] );
249                         if ( convertedValue != null )
250                         {
251                             value = convertedValue;
252                         }
253                     }
254                     // set property to value
255                     m.invoke( this, new Object[] { value } );
256                 }
257 	    	}
258 		    catch ( Exception exc )
259 		    {
260 		    	// show error and continue
261 		    	debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
262 		    }
263 		}
264 	    	
265     }
266 
267 	/***
268 	* Writes a message to the standard error stream.
269 	*/
270     public static void logString (String aString)
271     {
272     	System.err.println( aString );
273     }
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     	System.err.println( aString );
283     }
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