DefaultInvoker.java
// SECTION-START[License Header]
// <editor-fold defaultstate="collapsed" desc=" Generated License ">
/*
* Java Object Management and Configuration
* Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $JOMC: DefaultInvoker.java 5061 2015-05-31 13:20:40Z schulte $
*
*/
// </editor-fold>
// SECTION-END
package org.jomc.ri;
import java.lang.reflect.InvocationTargetException;
import org.jomc.model.Instance;
import org.jomc.spi.Invocation;
import org.jomc.spi.Invoker;
// SECTION-START[Documentation]
// <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
/**
* Default {@code Invoker} implementation.
*
* <dl>
* <dt><b>Identifier:</b></dt><dd>org.jomc.ri.DefaultInvoker</dd>
* <dt><b>Name:</b></dt><dd>JOMC ⁑ RI ⁑ DefaultInvoker</dd>
* <dt><b>Abstract:</b></dt><dd>No</dd>
* <dt><b>Final:</b></dt><dd>No</dd>
* <dt><b>Stateless:</b></dt><dd>No</dd>
* </dl>
*
* @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 1.0
* @version 1.0
*/
// </editor-fold>
// SECTION-END
// SECTION-START[Annotations]
// <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
@javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
// </editor-fold>
// SECTION-END
public class DefaultInvoker implements Invoker
{
// SECTION-START[DefaultInvoker]
/**
* Performs a method invocation on an object.
* <p>
* This method first passes the given invocation to the {@code preInvoke} method. If the result property of the
* invocation returned by the {@code preInvoke} method is an instance of {@code Throwable}, that instance will be
* thrown; otherwise the invocation returned by the {@code preInvoke} method is performed and then passed to the
* {@code postInvoke} method. If the result property of the invocation returned from the {@code postInvoke} method
* is an instance of {@code Throwable}, that instance will be thrown; otherwise the value of the result property is
* returned by this method.
* </p>
*
* @param invocation The invocation to perform.
*
* @return The return value of the invocation. If the declared return type of the method of the invocation is a
* primitive type, then the value returned by this method must be an instance of the corresponding primitive wrapper
* class; otherwise, it must be a type assignable to the declared return type of the method of the invocation.
* If the value returned by this method is {@code null} and the declared return type of the method of the invocation
* is primitive, then a {@code NullPointerException} will be thrown. If the value returned by this method is
* otherwise not compatible to the declared return type of the method of the invocation, a
* {@code ClassCastException} will be thrown.
*
* @throws Throwable The exception thrown from the method invocation. The exception's type must be assignable
* either to any of the exception types declared in the {@code throws} clause of the method of the invocation or to
* the unchecked exception types {@code java.lang.RuntimeException} or {@code java.lang.Error}.
* If a checked exception is thrown by this method that is not assignable to any of the exception types declared in
* the {@code throws} clause of the method of the invocation, then an {@code UndeclaredThrowableException}
* containing the exception that was thrown by this method will be thrown.
*
* @see #preInvoke(org.jomc.spi.Invocation)
* @see #postInvoke(org.jomc.spi.Invocation)
*/
public Object invoke( final Invocation invocation ) throws Throwable
{
Invocation current = invocation;
final Instance instance = (Instance) current.getContext().get( DefaultInvocation.INSTANCE_KEY );
try
{
if ( instance != null && instance.isStateless() )
{
try
{
current = this.preInvoke( current );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
if ( !( current.getResult() instanceof Throwable ) )
{
try
{
current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
}
try
{
current = this.postInvoke( current );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
if ( current.getResult() instanceof Throwable )
{
throw (Throwable) current.getResult();
}
return current.getResult();
}
else
{
synchronized ( invocation.getObject() )
{
try
{
current = this.preInvoke( current );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
if ( !( current.getResult() instanceof Throwable ) )
{
try
{
current.setResult( current.getMethod().invoke( current.getObject(),
current.getArguments() ) );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
}
try
{
current = this.postInvoke( current );
}
catch ( final Throwable t )
{
this.handleException( current, t );
}
if ( current.getResult() instanceof Throwable )
{
throw (Throwable) current.getResult();
}
return current.getResult();
}
}
}
finally
{
invocation.getContext().clear();
}
}
/**
* Called before an invocation is performed.
* <p>
* Overriding classes may use this method to perform any kind of operation prior to an invocation and to create
* custom invocation instances. If an overriding class wishes to throw an exception, it may do so by setting the
* result property of the returned invocation to an instance of {@code Throwable} thrown as the result of the
* invocation. If an overriding class wishes to provide a custom {@code Invocation} class, it may do so by returning
* a different instance from this method. By default, this method does nothing and returns the given invocation
* unchanged.
* </p>
*
* @param invocation The invocation about to be performed.
*
* @return The processed invocation.
*
* @throws NullPointerException if {@code invocation} is {@code null}.
*/
public Invocation preInvoke( final Invocation invocation )
{
if ( invocation == null )
{
throw new NullPointerException( "invocation" );
}
return invocation;
}
/**
* Called after an invocation has been performed.
* <p>
* Overriding classes may use this method to perform any kind of operation after an invocation has been
* performed and to maintain custom invocation instances. If an overriding class wishes to throw an exception, it
* may do so by setting the result property of the returned invocation to an instance of {@code Throwable} thrown as
* the result of the invocation. Since the result property of the given invocation already holds the result of the
* invocation (which may already be an instance of {@code Throwable}), care must be taken when updating that result.
* By default, this method does nothing and returns the given invocation unchanged.
* </p>
*
* @param invocation The performed invocation.
*
* @return The processed invocation.
*
* @throws NullPointerException if {@code invocation} is {@code null}.
*/
public Invocation postInvoke( final Invocation invocation )
{
if ( invocation == null )
{
throw new NullPointerException( "invocation" );
}
return invocation;
}
/**
* Called whenever an exception has been caught.
* <p>
* Overriding classes may use this method for handling exceptions. By default, this method updates the result of
* the given invocation with the given throwable. If that throwable is an instance of
* {@code InvocationTargetException}, this method updates the result with the value of that exception's target
* exception. If the result of the given invocation already is an instance of {@code Throwable}, this method does
* not update the result.
* </p>
*
* @param invocation The invocation to update.
* @param t The throwable to update {@code invocation} with.
*/
public void handleException( final Invocation invocation, final Throwable t )
{
if ( invocation != null && !( invocation.getResult() instanceof Throwable ) )
{
if ( t instanceof InvocationTargetException
&& ( (InvocationTargetException) t ).getTargetException() != null )
{
invocation.setResult( ( (InvocationTargetException) t ).getTargetException() );
return;
}
invocation.setResult( t );
}
}
// SECTION-END
// SECTION-START[Constructors]
// <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
/** Creates a new {@code DefaultInvoker} instance. */
@javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
public DefaultInvoker()
{
// SECTION-START[Default Constructor]
super();
// SECTION-END
}
// </editor-fold>
// SECTION-END
// SECTION-START[Dependencies]
// SECTION-END
// SECTION-START[Properties]
// SECTION-END
// SECTION-START[Messages]
// SECTION-END
}