View Javadoc
1   // SECTION-START[License Header]
2   // <editor-fold defaultstate="collapsed" desc=" Generated License ">
3   /*
4    * Java Object Management and Configuration
5    * Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
6    * All rights reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   *
12   *   o Redistributions of source code must retain the above copyright
13   *     notice, this list of conditions and the following disclaimer.
14   *
15   *   o Redistributions in binary form must reproduce the above copyright
16   *     notice, this list of conditions and the following disclaimer in
17   *     the documentation and/or other materials provided with the
18   *     distribution.
19   *
20   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22   * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * $JOMC: DefaultInvoker.java 5061 2015-05-31 13:20:40Z schulte $
32   *
33   */
34  // </editor-fold>
35  // SECTION-END
36  package org.jomc.ri;
37  
38  import java.lang.reflect.InvocationTargetException;
39  import org.jomc.model.Instance;
40  import org.jomc.spi.Invocation;
41  import org.jomc.spi.Invoker;
42  
43  // SECTION-START[Documentation]
44  // <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
45  /**
46   * Default {@code Invoker} implementation.
47   *
48   * <dl>
49   *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.DefaultInvoker</dd>
50   *   <dt><b>Name:</b></dt><dd>JOMC ⁑ RI ⁑ DefaultInvoker</dd>
51   *   <dt><b>Abstract:</b></dt><dd>No</dd>
52   *   <dt><b>Final:</b></dt><dd>No</dd>
53   *   <dt><b>Stateless:</b></dt><dd>No</dd>
54   * </dl>
55   *
56   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 1.0
57   * @version 1.0
58   */
59  // </editor-fold>
60  // SECTION-END
61  // SECTION-START[Annotations]
62  // <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
63  @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
64  // </editor-fold>
65  // SECTION-END
66  public class DefaultInvoker implements Invoker
67  {
68      // SECTION-START[DefaultInvoker]
69  
70      /**
71       * Performs a method invocation on an object.
72       * <p>
73       * This method first passes the given invocation to the {@code preInvoke} method. If the result property of the
74       * invocation returned by the {@code preInvoke} method is an instance of {@code Throwable}, that instance will be
75       * thrown; otherwise the invocation returned by the {@code preInvoke} method is performed and then passed to the
76       * {@code postInvoke} method. If the result property of the invocation returned from the {@code postInvoke} method
77       * is an instance of {@code Throwable}, that instance will be thrown; otherwise the value of the result property is
78       * returned by this method.
79       * </p>
80       *
81       * @param invocation The invocation to perform.
82       *
83       * @return The return value of the invocation. If the declared return type of the method of the invocation is a
84       * primitive type, then the value returned by this method must be an instance of the corresponding primitive wrapper
85       * class; otherwise, it must be a type assignable to the declared return type of the method of the invocation.
86       * If the value returned by this method is {@code null} and the declared return type of the method of the invocation
87       * is primitive, then a {@code NullPointerException} will be thrown. If the value returned by this method is
88       * otherwise not compatible to the declared return type of the method of the invocation, a
89       * {@code ClassCastException} will be thrown.
90       *
91       * @throws Throwable The exception thrown from the method invocation. The exception's type must be assignable
92       * either to any of the exception types declared in the {@code throws} clause of the method of the invocation or to
93       * the unchecked exception types {@code java.lang.RuntimeException} or {@code java.lang.Error}.
94       * If a checked exception is thrown by this method that is not assignable to any of the exception types declared in
95       * the {@code throws} clause of the method of the invocation, then an {@code UndeclaredThrowableException}
96       * containing the exception that was thrown by this method will be thrown.
97       *
98       * @see #preInvoke(org.jomc.spi.Invocation)
99       * @see #postInvoke(org.jomc.spi.Invocation)
100      */
101     public Object invoke( final Invocation invocation ) throws Throwable
102     {
103         Invocation current = invocation;
104         final Instance instance = (Instance) current.getContext().get( DefaultInvocation.INSTANCE_KEY );
105 
106         try
107         {
108             if ( instance != null && instance.isStateless() )
109             {
110                 try
111                 {
112                     current = this.preInvoke( current );
113                 }
114                 catch ( final Throwable t )
115                 {
116                     this.handleException( current, t );
117                 }
118 
119                 if ( !( current.getResult() instanceof Throwable ) )
120                 {
121                     try
122                     {
123                         current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) );
124                     }
125                     catch ( final Throwable t )
126                     {
127                         this.handleException( current, t );
128                     }
129                 }
130 
131                 try
132                 {
133                     current = this.postInvoke( current );
134                 }
135                 catch ( final Throwable t )
136                 {
137                     this.handleException( current, t );
138                 }
139 
140                 if ( current.getResult() instanceof Throwable )
141                 {
142                     throw (Throwable) current.getResult();
143                 }
144 
145                 return current.getResult();
146             }
147             else
148             {
149                 synchronized ( invocation.getObject() )
150                 {
151                     try
152                     {
153                         current = this.preInvoke( current );
154                     }
155                     catch ( final Throwable t )
156                     {
157                         this.handleException( current, t );
158                     }
159 
160                     if ( !( current.getResult() instanceof Throwable ) )
161                     {
162                         try
163                         {
164                             current.setResult( current.getMethod().invoke( current.getObject(),
165                                                                            current.getArguments() ) );
166 
167                         }
168                         catch ( final Throwable t )
169                         {
170                             this.handleException( current, t );
171                         }
172                     }
173 
174                     try
175                     {
176                         current = this.postInvoke( current );
177                     }
178                     catch ( final Throwable t )
179                     {
180                         this.handleException( current, t );
181                     }
182 
183                     if ( current.getResult() instanceof Throwable )
184                     {
185                         throw (Throwable) current.getResult();
186                     }
187 
188                     return current.getResult();
189                 }
190             }
191         }
192         finally
193         {
194             invocation.getContext().clear();
195         }
196     }
197 
198     /**
199      * Called before an invocation is performed.
200      * <p>
201      * Overriding classes may use this method to perform any kind of operation prior to an invocation and to create
202      * custom invocation instances. If an overriding class wishes to throw an exception, it may do so by setting the
203      * result property of the returned invocation to an instance of {@code Throwable} thrown as the result of the
204      * invocation. If an overriding class wishes to provide a custom {@code Invocation} class, it may do so by returning
205      * a different instance from this method. By default, this method does nothing and returns the given invocation
206      * unchanged.
207      * </p>
208      *
209      * @param invocation The invocation about to be performed.
210      *
211      * @return The processed invocation.
212      *
213      * @throws NullPointerException if {@code invocation} is {@code null}.
214      */
215     public Invocation preInvoke( final Invocation invocation )
216     {
217         if ( invocation == null )
218         {
219             throw new NullPointerException( "invocation" );
220         }
221 
222         return invocation;
223     }
224 
225     /**
226      * Called after an invocation has been performed.
227      * <p>
228      * Overriding classes may use this method to perform any kind of operation after an invocation has been
229      * performed and to maintain custom invocation instances. If an overriding class wishes to throw an exception, it
230      * may do so by setting the result property of the returned invocation to an instance of {@code Throwable} thrown as
231      * the result of the invocation. Since the result property of the given invocation already holds the result of the
232      * invocation (which may already be an instance of {@code Throwable}), care must be taken when updating that result.
233      * By default, this method does nothing and returns the given invocation unchanged.
234      * </p>
235      *
236      * @param invocation The performed invocation.
237      *
238      * @return The processed invocation.
239      *
240      * @throws NullPointerException if {@code invocation} is {@code null}.
241      */
242     public Invocation postInvoke( final Invocation invocation )
243     {
244         if ( invocation == null )
245         {
246             throw new NullPointerException( "invocation" );
247         }
248 
249         return invocation;
250     }
251 
252     /**
253      * Called whenever an exception has been caught.
254      * <p>
255      * Overriding classes may use this method for handling exceptions. By default, this method updates the result of
256      * the given invocation with the given throwable. If that throwable is an instance of
257      * {@code InvocationTargetException}, this method updates the result with the value of that exception's target
258      * exception. If the result of the given invocation already is an instance of {@code Throwable}, this method does
259      * not update the result.
260      * </p>
261      *
262      * @param invocation The invocation to update.
263      * @param t The throwable to update {@code invocation} with.
264      */
265     public void handleException( final Invocation invocation, final Throwable t )
266     {
267         if ( invocation != null && !( invocation.getResult() instanceof Throwable ) )
268         {
269             if ( t instanceof InvocationTargetException
270                      && ( (InvocationTargetException) t ).getTargetException() != null )
271             {
272                 invocation.setResult( ( (InvocationTargetException) t ).getTargetException() );
273                 return;
274             }
275 
276             invocation.setResult( t );
277         }
278     }
279 
280     // SECTION-END
281     // SECTION-START[Constructors]
282     // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
283     /** Creates a new {@code DefaultInvoker} instance. */
284     @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
285     public DefaultInvoker()
286     {
287         // SECTION-START[Default Constructor]
288         super();
289         // SECTION-END
290     }
291     // </editor-fold>
292     // SECTION-END
293     // SECTION-START[Dependencies]
294     // SECTION-END
295     // SECTION-START[Properties]
296     // SECTION-END
297     // SECTION-START[Messages]
298     // SECTION-END
299 
300 }