001 // SECTION-START[License Header]
002 // <editor-fold defaultstate="collapsed" desc=" Generated License ">
003 /*
004 * Copyright (c) 2009 The JOMC Project
005 * Copyright (c) 2005 Christian Schulte <cs@jomc.org>
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions
010 * are met:
011 *
012 * o Redistributions of source code must retain the above copyright
013 * notice, this list of conditions and the following disclaimer.
014 *
015 * o Redistributions in binary form must reproduce the above copyright
016 * notice, this list of conditions and the following disclaimer in
017 * the documentation and/or other materials provided with the
018 * distribution.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
029 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
030 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 *
032 * $Id: DefaultInvoker.java 1102 2009-12-07 03:01:58Z schulte2005 $
033 *
034 */
035 // </editor-fold>
036 // SECTION-END
037 package org.jomc.ri;
038
039 import java.lang.reflect.InvocationTargetException;
040 import org.jomc.model.Instance;
041 import org.jomc.spi.Invocation;
042 import org.jomc.spi.Invoker;
043
044 // SECTION-START[Documentation]
045 // <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
046 /**
047 * Default {@code Invoker} implementation.
048 * @see DefaultInvocation
049 *
050 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 1.0
051 * @version $Id: DefaultInvoker.java 1102 2009-12-07 03:01:58Z schulte2005 $
052 */
053 // </editor-fold>
054 // SECTION-END
055 // SECTION-START[Annotations]
056 // <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
057 @javax.annotation.Generated( value = "org.jomc.tools.JavaSources",
058 comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-11/jomc-tools" )
059 // </editor-fold>
060 // SECTION-END
061 public class DefaultInvoker implements Invoker
062 {
063 // SECTION-START[Invoker]
064
065 /**
066 * Performs a method invocation on an object.
067 * <p>This method first passes the given invocation to the {@code preInvoke} method. If the result property of the
068 * invocation returned by the {@code preInvoke} method is an instance of {@code Throwable}, that instance will be
069 * thrown; otherwise the invocation returned by the {@code preInvoke} method is performed and then passed to the
070 * {@code postInvoke} method. If the result property of the invocation returned from the {@code postInvoke} method
071 * is an instance of {@code Throwable}, that instance will be thrown; otherwise the value of the result property is
072 * returned by this method.</p>
073 *
074 * @param invocation The invocation to perform.
075 *
076 * @return The return value of the invocation. If the declared return type of the method of the invocation is a
077 * primitive type, then the value returned by this method must be an instance of the corresponding primitive wrapper
078 * class; otherwise, it must be a type assignable to the declared return type of the method of the invocation.
079 * If the value returned by this method is {@code null} and the declared return type of the method of the invocation
080 * is primitive, then a {@code NullPointerException} will be thrown. If the value returned by this method is
081 * otherwise not compatible to the declared return type of the method of the invocation, a
082 * {@code ClassCastException} will be thrown.
083 *
084 * @throws Throwable The exception thrown from the method invocation. The exception's type must be assignable
085 * either to any of the exception types declared in the {@code throws} clause of the method of the invocation or to
086 * the unchecked exception types {@code java.lang.RuntimeException} or {@code java.lang.Error}.
087 * If a checked exception is thrown by this method that is not assignable to any of the exception types declared in
088 * the {@code throws} clause of the method of the invocation, then an {@code UndeclaredThrowableException}
089 * containing the exception that was thrown by this method will be thrown.
090 *
091 * @see #preInvoke(org.jomc.spi.Invocation)
092 * @see #postInvoke(org.jomc.spi.Invocation)
093 */
094 public Object invoke( final Invocation invocation ) throws Throwable
095 {
096 Invocation current = invocation;
097 final Instance instance = (Instance) current.getContext().get( DefaultInvocation.INSTANCE_KEY );
098
099 try
100 {
101 if ( instance != null && instance.isStateless() )
102 {
103 try
104 {
105 current = this.preInvoke( current );
106 }
107 catch ( final Throwable t )
108 {
109 this.handleException( current, t );
110 }
111
112 if ( !( current.getResult() instanceof Throwable ) )
113 {
114 try
115 {
116 current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) );
117 }
118 catch ( final Throwable t )
119 {
120 this.handleException( current, t );
121 }
122 }
123
124 try
125 {
126 current = this.postInvoke( current );
127 }
128 catch ( final Throwable t )
129 {
130 this.handleException( current, t );
131 }
132
133 if ( current.getResult() instanceof Throwable )
134 {
135 throw (Throwable) current.getResult();
136 }
137
138 return current.getResult();
139 }
140 else
141 {
142 synchronized ( invocation.getObject() )
143 {
144 try
145 {
146 current = this.preInvoke( current );
147 }
148 catch ( final Throwable t )
149 {
150 this.handleException( current, t );
151 }
152
153 if ( !( current.getResult() instanceof Throwable ) )
154 {
155 try
156 {
157 current.setResult( current.getMethod().invoke( current.getObject(),
158 current.getArguments() ) );
159
160 }
161 catch ( final Throwable t )
162 {
163 this.handleException( current, t );
164 }
165 }
166
167 try
168 {
169 current = this.postInvoke( current );
170 }
171 catch ( final Throwable t )
172 {
173 this.handleException( current, t );
174 }
175
176 if ( current.getResult() instanceof Throwable )
177 {
178 throw (Throwable) current.getResult();
179 }
180
181 return current.getResult();
182 }
183 }
184 }
185 finally
186 {
187 invocation.getContext().clear();
188 }
189 }
190
191 // SECTION-END
192 // SECTION-START[DefaultInvoker]
193 /**
194 * Called before an invocation is performed.
195 * <p>Overriding classes may use this method to perform any kind of operation prior to an invocation and to create
196 * custom invocation instances. If an overriding class wishes to throw an exception, it may do so by setting the
197 * result property of the returned invocation to an instance of {@code Throwable} thrown as the result of the
198 * invocation. If an overriding class wishes to provide a custom {@code Invocation} class, it may do so by returning
199 * a different instance from this method. By default, this method does nothing and returns the given invocation
200 * unchanged.</p>
201 *
202 * @param invocation The invocation about to be performed.
203 *
204 * @return The processed invocation.
205 *
206 * @throws NullPointerException if {@code invocation} is {@code null}.
207 */
208 public Invocation preInvoke( final Invocation invocation )
209 {
210 if ( invocation == null )
211 {
212 throw new NullPointerException( "invocation" );
213 }
214
215 return invocation;
216 }
217
218 /**
219 * Called after an invocation has been performed.
220 * <p>Overriding classes may use this method to perform any kind of operation after an invocation has been
221 * performed and to maintain custom invocation instances. If an overriding class wishes to throw an exception, it
222 * may do so by setting the result property of the returned invocation to an instance of {@code Throwable} thrown as
223 * the result of the invocation. Since the result property of the given invocation already holds the result of the
224 * invocation (which may already be an instance of {@code Throwable}), care must be taken when updating that result.
225 * By default, this method does nothing and returns the given invocation unchanged.</p>
226 *
227 * @param invocation The performed invocation.
228 *
229 * @return The processed invocation.
230 *
231 * @throws NullPointerException if {@code invocation} is {@code null}.
232 */
233 public Invocation postInvoke( final Invocation invocation )
234 {
235 if ( invocation == null )
236 {
237 throw new NullPointerException( "invocation" );
238 }
239
240 return invocation;
241 }
242
243 /**
244 * Called whenever an exception has been caught.
245 * <p>Overriding classes may use this method for handling exceptions. By default, this method updates the result of
246 * the given invocation with the given throwable. If that throwable is an instance of
247 * {@code InvocationTargetException}, this method updates the result with the value of that exception's target
248 * exception. If the result of the given invocation already is an instance of {@code Throwable}, this method does
249 * not update the result.</p>
250 *
251 * @param invocation The invocation to update.
252 * @param t The throwable to update {@code invocation} with.
253 */
254 public void handleException( final Invocation invocation, final Throwable t )
255 {
256 if ( invocation != null && !( invocation.getResult() instanceof Throwable ) )
257 {
258 if ( t instanceof InvocationTargetException &&
259 ( (InvocationTargetException) t ).getTargetException() != null )
260 {
261 invocation.setResult( ( (InvocationTargetException) t ).getTargetException() );
262 return;
263 }
264
265 invocation.setResult( t );
266 }
267 }
268
269 // SECTION-END
270 // SECTION-START[Constructors]
271 // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
272
273 /** Creates a new {@code DefaultInvoker} instance. */
274 @javax.annotation.Generated( value = "org.jomc.tools.JavaSources",
275 comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-11/jomc-tools" )
276 public DefaultInvoker()
277 {
278 // SECTION-START[Default Constructor]
279 super();
280 // SECTION-END
281 }
282 // </editor-fold>
283 // SECTION-END
284 // SECTION-START[Dependencies]
285 // SECTION-END
286 // SECTION-START[Properties]
287 // SECTION-END
288 // SECTION-START[Messages]
289 // SECTION-END
290 }