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 4588 2012-06-03 06:01:30Z schulte2005 $
032 *
033 */
034// </editor-fold>
035// SECTION-END
036package org.jomc.ri;
037
038import java.lang.reflect.InvocationTargetException;
039import org.jomc.model.Instance;
040import org.jomc.spi.Invocation;
041import 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.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
064// </editor-fold>
065// SECTION-END
066public 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.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
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}