1 /*
2 Copyright (c) 2003, Laurent Caillette.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modifica-
6 tion, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14
15 3. The end-user documentation included with the redistribution, if any, must
16 include the following acknowledgment: "This product includes software
17 written by Laurent Caillette."
18 Alternately, this acknowledgment may appear in the software itself, if
19 and wherever such third-party acknowledgments normally appear.
20
21 4. The name "Laurent Caillette" must not be used to endorse or
22 promote products derived from this software without
23 prior written permission. For written permission, please contact
24 laurent.caillette@laposte.net
25
26 5. Products derived from this software may not be called
27 "Laurent Caillette", nor may "Laurent Caillette" appear
28 in their name, without prior written permission of the
29 author.
30
31 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
32 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
33 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 AUTHOR (LAURENT CAILLETTE) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
36 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
37 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42 package tweed.invocation;
43 import org.apache.avalon.framework.logger.AbstractLogEnabled;
44 import tweed.context.Context;
45 import tweed.system.FunctionalException;
46
47 /***
48 * The base class for implementing <code>Command</code> objects, which
49 * represent a server-side processing.
50 * <p>
51 * This is the typical lifecycle of a <code>Command</code> object:
52 * <ol>
53 * <li>
54 * Instantiation is done client-side giving only a <code>Context</code>
55 * as input parameter. The <code>Context</code> object must be available
56 * in the application.
57 * <pre>
58 * MyConcreteCommand command = new MyConcreteCommand( context ) ;
59 * </pre>
60 * All fields are set to default values.
61 * </li><li>
62 * Then, client code fills up input parameters,
63 * using setters defined in the concrete Command class.
64 * "Input" and "output" parameters mean from the server's point of view.
65 * <pre>
66 * command.setCustomerId( theId ) ;
67 * </pre>
68 * </li><li>
69 * Once parameters in have been set, the client asks the method to
70 * execute:
71 * <pre>
72 * command.execute() ;
73 * </pre>
74 * The command "magically" appears on the server, with input
75 * (and in-out) parameters set to the same values as client-side.
76 * Output-only parameters have been cleaned up (reset to their
77 * default value).
78 * The command executes the body of its <code>execute()</code> method.
79 * This may set the value of output parameters.
80 * </li><li>
81 * The updated fields are (output and in-out parameters) "magically"
82 * set in the invoked command, as we're back on the client-side.
83 * They can now be accessed using the getters. Input-only parameters
84 * are left same as before command execution.
85 * <pre>
86 * Customer result = command.getCustomer() ;
87 * </pre>
88 * </li>
89 * </ol>
90 *
91 * A <code>Command</code> object may be reused as many times as needed,
92 * but special care should be taken to not pollute one call with input
93 * parameter values remaining from a previous call.
94 *
95 * <p>
96 * <b>Tagging fields used as input or output parameters:</b><br>
97 * <ul>
98 * <li>
99 * All fields used as input, output, or in-out parameters MUST NOT
100 * be static, nor final, nor transient. They can be private, or protected.
101 * Public and package-private modifiers are also supported, though not
102 * recommended.
103 * <li></li>
104 * Fields used as input parameters MUST be prefixed with "in_".
105 * <li></li>
106 * Fields used as output parameters MUST be prefixed with "out_".
107 * <li></li>
108 * Fields used as in-out parameters MUST be prefixed with "in_out_".
109 * </li>
110 * </ul>
111 * Fields which do not respect constraints above won't be treated as
112 * parameters, they won't travel between client and server.
113 *
114 * <p>
115 * <b>Serialization</b><br>
116 * A concrete <code>Command</code> does not need to be serializable, since
117 * fields will be extracted in another object for travelling between
118 * client and server.
119 * All fields used as input/output parameters MUST be serializable.
120 *
121 * <p>
122 * <b>Use of Command as Model:</b><br>
123 * "Model" is used in the bindings.
124 * A concrete <code>Command</code> may be used as a Model.
125 *
126 * <p>
127 * <b>Declaring a <code>Command</code> as nested class:</b><br>
128 * This is strictly forbidden.
129 *
130 * @author Laurent Caillette
131 * @version $Id$
132 */
133 public abstract class Command
134 extends AbstractLogEnabled
135 {
136
137 private final transient Context context ;
138 boolean ran = false ;
139
140 protected Command( Context context ) {
141 if( context == null ) {
142 throw new NullPointerException( "context" ) ;
143 }
144 this.context = context ;
145 enableLogging( context.getLogger().getChildLogger(
146 getClass().getName() ) ) ;
147 }
148
149 public final Context getContext() {
150 return context ;
151 }
152
153 public final static String SERVERSIDE_CLASSNAME_PREFIX = "ServerSide" ;
154
155 public String getServerSideClassName() {
156 String fqn = getClass().getName() ;
157 int startOfClassName = fqn.lastIndexOf( '.') ;
158 String packageName = fqn.substring( 0, startOfClassName ) ;
159 String shortClassName = fqn.substring( startOfClassName + 1 ) ;
160 return
161 packageName + "." +
162 SERVERSIDE_CLASSNAME_PREFIX +
163 shortClassName
164 ;
165 }
166
167 /*package*/ final static String EXECUTE_METHOD_NAME = "execute" /package-summary.html">color="#329900">package*/ final static String EXECUTE_METHOD_NAME = "execute" ;
168
169
170 /***
171 * <code>"in_"</code> is the prefix for tagging input parameters.
172 */
173 public final static String PARAM_IN_PREFIX = "in_" ;
174
175 /***
176 * <code>"out_"</code> is the prefix for tagging output parameters.
177 */
178 public final static String PARAM_OUT_PREFIX = "out_" ;
179
180 /***
181 * <code>"in_out_"</code> is the prefix for tagging input parameters.
182 */
183 public final static String PARAM_INOUT_PREFIX = "in_out_" ;
184
185 /***
186 * Override this method for the processings which should occur server-side.
187 */
188 protected void doExecute() throws FunctionalException {
189 RuntimeException ex = null ;
190 if( getContext().isServerSide() ) {
191 ex = new RuntimeException(
192 "No implementation for doExecute() method " +
193 "of " + getClass().getName()
194 ) ;
195 } else {
196 ex = new RuntimeException(
197 "doExecute() should never be invoked client-side" ) ;
198 }
199 throw ex ;
200 }
201
202 private FunctionalException exception = null ;
203
204 </*package*/ final void setException( FunctionalException exception ) {/package-summary/html">color="#329900">package*/ final void setException( FunctionalException exception ) {/package-summary.html">font color="#329900">/*package*/ final void setException( FunctionalException exception ) {/package-summary.html">color="#329900">package*/ final void setException( FunctionalException exception ) {
205 this.exception = exception ;
206 }
207
208 public final Exception getFunctionalException() {
209 return exception ;
210 }
211
212 public final boolean wasSuccess() {
213 return exception == null ;
214 }
215
216 public final void execute() throws FunctionalException {
217 if( getContext().isClientSide() ) {
218 getContext().getInvoker().invoke( this ) ;
219 } else {
220 doExecute() ;
221 }
222 }
223
224
225
226 }
This page was automatically generated by Maven