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 968 2009-11-18 06:08:28Z 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 968 2009-11-18 06:08:28Z 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-8/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                    current = this.preInvoke( current );
104                    if ( current.getResult() instanceof Throwable )
105                    {
106                        throw (Throwable) current.getResult();
107                    }
108    
109                    try
110                    {
111                        current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) );
112                    }
113                    catch ( final InvocationTargetException e )
114                    {
115                        current.setResult( e.getTargetException() != null ? e.getTargetException() : e );
116                    }
117                    catch ( final Throwable t )
118                    {
119                        current.setResult( t );
120                    }
121    
122                    current = this.postInvoke( current );
123                    if ( current.getResult() instanceof Throwable )
124                    {
125                        throw (Throwable) current.getResult();
126                    }
127                }
128                else
129                {
130                    synchronized ( invocation.getObject() )
131                    {
132                        current = this.preInvoke( current );
133                        if ( current.getResult() instanceof Throwable )
134                        {
135                            throw (Throwable) current.getResult();
136                        }
137    
138                        try
139                        {
140                            current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) );
141                        }
142                        catch ( final InvocationTargetException e )
143                        {
144                            current.setResult( e.getTargetException() != null ? e.getTargetException() : e );
145                        }
146                        catch ( final Throwable t )
147                        {
148                            current.setResult( t );
149                        }
150    
151                        current = this.postInvoke( current );
152                        if ( current.getResult() instanceof Throwable )
153                        {
154                            throw (Throwable) current.getResult();
155                        }
156                    }
157                }
158    
159                return current.getResult();
160            }
161            finally
162            {
163                invocation.getContext().clear();
164            }
165        }
166    
167        // SECTION-END
168        // SECTION-START[DefaultInvoker]
169        /**
170         * Called before an invocation is performed.
171         * <p>Overriding classes may use this method to perform any kind of operation prior to an invocation and to create
172         * custom invocation instances. If an overriding class wishes to throw an exception, it may do so by setting the
173         * result property of the returned invocation to an instance of {@code Throwable} thrown as the result of the
174         * invocation. If an overriding class wishes to provide a custom {@code Invocation} class, it may do so by returning
175         * a different instance from this method. By default, this method does nothing and returns the given invocation
176         * unchanged.</p>
177         *
178         * @param invocation The invocation about to be performed.
179         *
180         * @return The processed invocation.
181         *
182         * @throws NullPointerException if {@code invocation} is {@code null}.
183         */
184        public Invocation preInvoke( final Invocation invocation )
185        {
186            if ( invocation == null )
187            {
188                throw new NullPointerException( "invocation" );
189            }
190    
191            return invocation;
192        }
193    
194        /**
195         * Called after an invocation has been performed.
196         * <p>Overriding classes may use this method to perform any kind of operation after an invocation has been
197         * performed and to maintain custom invocation instances. If an overriding class wishes to throw an exception, it
198         * may do so by setting the result property of the returned invocation to an instance of {@code Throwable} thrown as
199         * the result of the invocation. Since the result property of the given invocation already holds the result of the
200         * invocation (which may already be an instance of {@code Throwable}), care must be taken when updating that result.
201         * By default, this method does nothing and returns the given invocation unchanged.</p>
202         *
203         * @param invocation The performed invocation.
204         *
205         * @return The processed invocation.
206         *
207         * @throws NullPointerException if {@code invocation} is {@code null}.
208         */
209        public Invocation postInvoke( final Invocation invocation )
210        {
211            if ( invocation == null )
212            {
213                throw new NullPointerException( "invocation" );
214            }
215    
216            return invocation;
217        }
218    
219        // SECTION-END
220        // SECTION-START[Constructors]
221        // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
222    
223        /** Creates a new {@code DefaultInvoker} instance. */
224        @javax.annotation.Generated( value = "org.jomc.tools.JavaSources",
225                                     comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-8/jomc-tools" )
226        public DefaultInvoker()
227        {
228            // SECTION-START[Default Constructor]
229            super();
230            // SECTION-END
231        }
232        // </editor-fold>
233        // SECTION-END
234        // SECTION-START[Dependencies]
235        // SECTION-END
236        // SECTION-START[Properties]
237        // SECTION-END
238        // SECTION-START[Messages]
239        // SECTION-END
240    }