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