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 1102 2009-12-07 03:01:58Z 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 1102 2009-12-07 03:01:58Z 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-11/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 try 104 { 105 current = this.preInvoke( current ); 106 } 107 catch ( final Throwable t ) 108 { 109 this.handleException( current, t ); 110 } 111 112 if ( !( current.getResult() instanceof Throwable ) ) 113 { 114 try 115 { 116 current.setResult( current.getMethod().invoke( current.getObject(), current.getArguments() ) ); 117 } 118 catch ( final Throwable t ) 119 { 120 this.handleException( current, t ); 121 } 122 } 123 124 try 125 { 126 current = this.postInvoke( current ); 127 } 128 catch ( final Throwable t ) 129 { 130 this.handleException( current, t ); 131 } 132 133 if ( current.getResult() instanceof Throwable ) 134 { 135 throw (Throwable) current.getResult(); 136 } 137 138 return current.getResult(); 139 } 140 else 141 { 142 synchronized ( invocation.getObject() ) 143 { 144 try 145 { 146 current = this.preInvoke( current ); 147 } 148 catch ( final Throwable t ) 149 { 150 this.handleException( current, t ); 151 } 152 153 if ( !( current.getResult() instanceof Throwable ) ) 154 { 155 try 156 { 157 current.setResult( current.getMethod().invoke( current.getObject(), 158 current.getArguments() ) ); 159 160 } 161 catch ( final Throwable t ) 162 { 163 this.handleException( current, t ); 164 } 165 } 166 167 try 168 { 169 current = this.postInvoke( current ); 170 } 171 catch ( final Throwable t ) 172 { 173 this.handleException( current, t ); 174 } 175 176 if ( current.getResult() instanceof Throwable ) 177 { 178 throw (Throwable) current.getResult(); 179 } 180 181 return current.getResult(); 182 } 183 } 184 } 185 finally 186 { 187 invocation.getContext().clear(); 188 } 189 } 190 191 // SECTION-END 192 // SECTION-START[DefaultInvoker] 193 /** 194 * Called before an invocation is performed. 195 * <p>Overriding classes may use this method to perform any kind of operation prior to an invocation and to create 196 * custom invocation instances. If an overriding class wishes to throw an exception, it may do so by setting the 197 * result property of the returned invocation to an instance of {@code Throwable} thrown as the result of the 198 * invocation. If an overriding class wishes to provide a custom {@code Invocation} class, it may do so by returning 199 * a different instance from this method. By default, this method does nothing and returns the given invocation 200 * unchanged.</p> 201 * 202 * @param invocation The invocation about to be performed. 203 * 204 * @return The processed invocation. 205 * 206 * @throws NullPointerException if {@code invocation} is {@code null}. 207 */ 208 public Invocation preInvoke( final Invocation invocation ) 209 { 210 if ( invocation == null ) 211 { 212 throw new NullPointerException( "invocation" ); 213 } 214 215 return invocation; 216 } 217 218 /** 219 * Called after an invocation has been performed. 220 * <p>Overriding classes may use this method to perform any kind of operation after an invocation has been 221 * performed and to maintain custom invocation instances. If an overriding class wishes to throw an exception, it 222 * may do so by setting the result property of the returned invocation to an instance of {@code Throwable} thrown as 223 * the result of the invocation. Since the result property of the given invocation already holds the result of the 224 * invocation (which may already be an instance of {@code Throwable}), care must be taken when updating that result. 225 * By default, this method does nothing and returns the given invocation unchanged.</p> 226 * 227 * @param invocation The performed invocation. 228 * 229 * @return The processed invocation. 230 * 231 * @throws NullPointerException if {@code invocation} is {@code null}. 232 */ 233 public Invocation postInvoke( final Invocation invocation ) 234 { 235 if ( invocation == null ) 236 { 237 throw new NullPointerException( "invocation" ); 238 } 239 240 return invocation; 241 } 242 243 /** 244 * Called whenever an exception has been caught. 245 * <p>Overriding classes may use this method for handling exceptions. By default, this method updates the result of 246 * the given invocation with the given throwable. If that throwable is an instance of 247 * {@code InvocationTargetException}, this method updates the result with the value of that exception's target 248 * exception. If the result of the given invocation already is an instance of {@code Throwable}, this method does 249 * not update the result.</p> 250 * 251 * @param invocation The invocation to update. 252 * @param t The throwable to update {@code invocation} with. 253 */ 254 public void handleException( final Invocation invocation, final Throwable t ) 255 { 256 if ( invocation != null && !( invocation.getResult() instanceof Throwable ) ) 257 { 258 if ( t instanceof InvocationTargetException && 259 ( (InvocationTargetException) t ).getTargetException() != null ) 260 { 261 invocation.setResult( ( (InvocationTargetException) t ).getTargetException() ); 262 return; 263 } 264 265 invocation.setResult( t ); 266 } 267 } 268 269 // SECTION-END 270 // SECTION-START[Constructors] 271 // <editor-fold defaultstate="collapsed" desc=" Generated Constructors "> 272 273 /** Creates a new {@code DefaultInvoker} instance. */ 274 @javax.annotation.Generated( value = "org.jomc.tools.JavaSources", 275 comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-11/jomc-tools" ) 276 public DefaultInvoker() 277 { 278 // SECTION-START[Default Constructor] 279 super(); 280 // SECTION-END 281 } 282 // </editor-fold> 283 // SECTION-END 284 // SECTION-START[Dependencies] 285 // SECTION-END 286 // SECTION-START[Properties] 287 // SECTION-END 288 // SECTION-START[Messages] 289 // SECTION-END 290 }