001    /*
002     * Copyright © 2008, 2009 Pedro Agulló Soliveres.
003     * 
004     * This file is part of DirectJNgine.
005     *
006     * DirectJNgine is free software: you can redistribute it and/or modify
007     * it under the terms of the GNU General Public License as published by
008     * the Free Software Foundation, either version 3 of the License.
009     *
010     * Commercial use is permitted to the extent that the code/component(s)
011     * do NOT become part of another Open Source or Commercially developed
012     * licensed development library or toolkit without explicit permission.
013     *
014     * DirectJNgine is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017     * GNU General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with DirectJNgine.  If not, see <http://www.gnu.org/licenses/>.
021     * 
022     * This software uses the ExtJs library (http://extjs.com), which is 
023     * distributed under the GPL v3 license (see http://extjs.com/license).
024     */
025    
026    package com.softwarementors.extjs.djn.router.dispatcher;
027    
028    import java.lang.reflect.Constructor;
029    import java.lang.reflect.InvocationTargetException;
030    import java.lang.reflect.Method;
031    import java.lang.reflect.Modifier;
032    
033    import com.softwarementors.extjs.djn.ClassUtils;
034    import com.softwarementors.extjs.djn.Timer;
035    import com.softwarementors.extjs.djn.router.processor.RequestException;
036    
037    public class Dispatcher {
038      
039      public Dispatcher() {
040        super();
041      }
042        
043      public Object dispatch( Class<?> instanceClass, Method method, Object[] parameters ) { 
044        int expectedArgumentCount = method.getParameterTypes().length;
045        if( parameters.length != expectedArgumentCount ) {
046          throw RequestException.forWrongMethodArgumentCount( method, expectedArgumentCount, parameters.length );
047        }
048          
049        Timer timer = new Timer();
050        try {
051          Object actionInstance = null;
052          if( !Modifier.isStatic(method.getModifiers())) {
053            actionInstance = createActionInstance(instanceClass);
054          }
055          Object result = invokeMethod( method, actionInstance, parameters);
056          return result;
057        }
058        finally {
059          timer.stop();
060          timer.logDebugTimeInMilliseconds("  - Java method dispatch time (" + ClassUtils.getSimpleName(method.getDeclaringClass()) + "." + method.getName() + ")" );
061        }
062      }
063    
064      protected Object createActionInstance(Class<?> instanceClass) {
065        Object actionInstance;
066        try {
067          Constructor<?> c = instanceClass.getConstructor();
068          // Invoke private constructors too
069          boolean accessible = c.isAccessible();
070          try {
071            c.setAccessible(true);
072            actionInstance = c.newInstance();
073          }
074          finally {
075            c.setAccessible(accessible);
076          }
077          return actionInstance;
078        }
079        catch (InstantiationException e) {
080          throw createUnableToCreateInstanceException(instanceClass, e);
081        }
082        catch (IllegalAccessException e) {
083          throw createUnableToCreateInstanceException(instanceClass, e);
084        }
085        catch (SecurityException e) {
086          throw createUnableToCreateInstanceException(instanceClass, e);
087        }
088        catch (NoSuchMethodException e) {
089          throw createUnableToCreateInstanceException(instanceClass, e);
090        }
091        catch (IllegalArgumentException e) {
092          throw createUnableToCreateInstanceException(instanceClass, e);
093        }
094        catch (InvocationTargetException e) {
095          throw createUnableToCreateInstanceException(instanceClass, e);
096        }
097      }
098    
099      protected MethodExecutionException createUnableToCreateInstanceException(Class<?> instanceClass, Throwable e) {
100        return MethodExecutionException.forUnableToCreateClassInstance( instanceClass, e );
101      }
102    
103      private Object invokeMethod(Method method, Object actionInstance, Object[] parameters) {
104        assert method != null;
105        assert parameters != null;
106        
107        Object result;
108        try {      
109          // Invoke private methods too!
110          boolean accessible = method.isAccessible();
111          try {
112            method.setAccessible(true);
113            result = method.invoke( actionInstance, parameters );
114          }
115          finally {
116            method.setAccessible(accessible);
117          }
118        }
119        catch (IllegalArgumentException e) {
120          throw createMethodInvocationError(method, e);
121        }
122        catch (IllegalAccessException e) {
123          throw createMethodInvocationError(method, e);
124        }
125        catch (InvocationTargetException e) {
126          throw createMethodInvocationError(method, e);
127        }
128        return result;
129      }
130    
131      private MethodExecutionException createMethodInvocationError(Method method, Throwable e) {
132        return MethodExecutionException.forMethodInvocationError( method, e );
133      }
134    
135    }