View Javadoc
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