Home » apache-cxf-2.1.1-src » org.apache » cxf » service » invoker » [javadoc | source]
    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements. See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership. The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License. You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied. See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.
   18    */
   19   
   20   package org.apache.cxf.service.invoker;
   21   
   22   import java.lang.reflect.InvocationTargetException;
   23   import java.lang.reflect.Method;
   24   import java.lang.reflect.Proxy;
   25   import java.util.Arrays;
   26   import java.util.List;
   27   import java.util.logging.Level;
   28   import java.util.logging.Logger;
   29   
   30   import org.apache.cxf.common.i18n.Message;
   31   import org.apache.cxf.common.logging.LogUtils;
   32   import org.apache.cxf.frontend.MethodDispatcher;
   33   import org.apache.cxf.helpers.CastUtils;
   34   import org.apache.cxf.interceptor.Fault;
   35   import org.apache.cxf.message.Exchange;
   36   import org.apache.cxf.message.FaultMode;
   37   import org.apache.cxf.message.MessageContentsList;
   38   import org.apache.cxf.service.Service;
   39   import org.apache.cxf.service.model.BindingOperationInfo;
   40   
   41   /**
   42    * Abstract implementation of Invoker.
   43    * <p>
   44    */
   45   public abstract class AbstractInvoker implements Invoker {
   46       private static final Logger LOG = LogUtils.getL7dLogger(AbstractInvoker.class);
   47       
   48       
   49       public Object invoke(Exchange exchange, Object o) {
   50   
   51           final Object serviceObject = getServiceObject(exchange);
   52           try {
   53   
   54               BindingOperationInfo bop = exchange.get(BindingOperationInfo.class);
   55               MethodDispatcher md = (MethodDispatcher) 
   56                   exchange.get(Service.class).get(MethodDispatcher.class.getName());
   57               Method m = md.getMethod(bop);
   58               //Method m = (Method)bop.getOperationInfo().getProperty(Method.class.getName());
   59               m = matchMethod(m, serviceObject);
   60               
   61               List<Object> params = null;
   62               if (o instanceof List) {
   63                   params = CastUtils.cast((List<?>)o);
   64               } else if (o != null) {
   65                   params = new MessageContentsList(o);
   66               }
   67               
   68               return invoke(exchange, serviceObject, m, params);
   69           } finally {
   70               releaseServiceObject(exchange, serviceObject);
   71           }
   72       }
   73   
   74       protected Object invoke(Exchange exchange, final Object serviceObject, Method m, List<Object> params) {
   75           Object res;
   76           try {
   77               Object[] paramArray = new Object[]{};
   78               if (params != null) {
   79                   paramArray = params.toArray();
   80               }
   81   
   82               res = performInvocation(exchange, serviceObject, m, paramArray);
   83               
   84               if (exchange.isOneWay()) {
   85                   return null;
   86               }
   87               
   88               return new MessageContentsList(res);
   89           } catch (InvocationTargetException e) {
   90               Throwable t = e.getCause();
   91               if (t == null) {
   92                   t = e;
   93               }
   94               exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
   95               for (Class<?> cl : m.getExceptionTypes()) {
   96                   if (cl.isInstance(t)) {
   97                       exchange.getInMessage().put(FaultMode.class, 
   98                                                   FaultMode.CHECKED_APPLICATION_FAULT);                    
   99                   }
  100               }
  101               
  102               if (t instanceof Fault) {
  103                   exchange.getInMessage().put(FaultMode.class, 
  104                                               FaultMode.CHECKED_APPLICATION_FAULT);                    
  105                   throw (Fault)t;
  106               }
  107               throw createFault(t, m, params, true);
  108           } catch (Fault f) {
  109               exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
  110               throw f;
  111           } catch (Exception e) {
  112               exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
  113               throw createFault(e, m, params, false);
  114           }
  115       }
  116       
  117       protected Fault createFault(Throwable ex, Method m, List<Object> params, boolean checked) {
  118           if (checked) {
  119               return new Fault(ex);
  120           } else {
  121               return new Fault(new Message("EXCEPTION_INVOKING_OBJECT",
  122                                            LOG,
  123                                            ex.getMessage(), m.toString(), params),
  124                                            ex);
  125           }
  126       }
  127       
  128       protected Object performInvocation(Exchange exchange, final Object serviceObject, Method m,
  129                                          Object[] paramArray) throws Exception {
  130           paramArray = insertExchange(m, paramArray, exchange);
  131           if (LOG.isLoggable(Level.FINER)) {
  132               LOG.log(Level.FINER, "INVOKING_METHOD", new Object[] {serviceObject, 
  133                                                                     m,
  134                                                                     Arrays.asList(paramArray)});
  135           }
  136           return m.invoke(serviceObject, paramArray);
  137       }
  138   
  139       public Object[] insertExchange(Method method, Object[] params, Exchange context) {
  140           Object[] newParams = params;
  141           for (int i = 0; i < method.getParameterTypes().length; i++) {
  142               if (method.getParameterTypes()[i].equals(Exchange.class)) {
  143                   newParams = new Object[params.length + 1];
  144   
  145                   for (int j = 0; j < newParams.length; j++) {
  146                       if (j == i) {
  147                           newParams[j] = context;
  148                       } else if (j > i) {
  149                           newParams[j] = params[j - 1];
  150                       } else {
  151                           newParams[j] = params[j];
  152                       }
  153                   }
  154               }
  155           }
  156           return newParams;
  157       }
  158       
  159       /**
  160        * Creates and returns a service object depending on the scope.
  161        */
  162       public abstract Object getServiceObject(final Exchange context);
  163   
  164       /**
  165        * Called when the invoker is done with the object.   Default implementation
  166        * does nothing.
  167        * @param context
  168        * @param obj
  169        */
  170       public void releaseServiceObject(final Exchange context, Object obj) {
  171       }
  172   
  173       /**
  174        * Returns a Method that has the same declaring class as the class of
  175        * targetObject to avoid the IllegalArgumentException when invoking the
  176        * method on the target object. The methodToMatch will be returned if the
  177        * targetObject doesn't have a similar method.
  178        * 
  179        * @param methodToMatch The method to be used when finding a matching method
  180        *            in targetObject
  181        * @param targetObject The object to search in for the method.
  182        * @return The methodToMatch if no such method exist in the class of
  183        *         targetObject; otherwise, a method from the class of targetObject
  184        *         matching the matchToMethod method.
  185        */
  186       private static Method matchMethod(Method methodToMatch, Object targetObject) {
  187           if (isJdkDynamicProxy(targetObject)) {
  188               Class[] interfaces = targetObject.getClass().getInterfaces();
  189               for (int i = 0; i < interfaces.length; i++) {
  190                   Method m = getMostSpecificMethod(methodToMatch, interfaces[i]);
  191                   if (!methodToMatch.equals(m)) {
  192                       return m;
  193                   }
  194               }
  195           }
  196           return methodToMatch;
  197       }
  198   
  199       /**
  200        * Return whether the given object is a J2SE dynamic proxy.
  201        * 
  202        * @param object the object to check
  203        * @see java.lang.reflect.Proxy#isProxyClass
  204        */
  205       public static boolean isJdkDynamicProxy(Object object) {
  206           return object != null && Proxy.isProxyClass(object.getClass());
  207       }
  208   
  209       /**
  210        * Given a method, which may come from an interface, and a targetClass used
  211        * in the current AOP invocation, find the most specific method if there is
  212        * one. E.g. the method may be IFoo.bar() and the target class may be
  213        * DefaultFoo. In this case, the method may be DefaultFoo.bar(). This
  214        * enables attributes on that method to be found.
  215        * 
  216        * @param method method to be invoked, which may come from an interface
  217        * @param targetClass target class for the curren invocation. May be
  218        *            <code>null</code> or may not even implement the method.
  219        * @return the more specific method, or the original method if the
  220        *         targetClass doesn't specialize it or implement it or is null
  221        */
  222       public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
  223           if (method != null && targetClass != null) {
  224               try {
  225                   method = targetClass.getMethod(method.getName(), method.getParameterTypes());
  226               } catch (NoSuchMethodException ex) {
  227                   // Perhaps the target class doesn't implement this method:
  228                   // that's fine, just use the original method
  229               }
  230           }
  231           return method;
  232       }
  233   }

Save This Page
Home » apache-cxf-2.1.1-src » org.apache » cxf » service » invoker » [javadoc | source]