/*
 * Copyright 2006-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.openspaces.core.executor.internal;

import com.gigaspaces.annotation.pojo.SpaceRouting;
import org.openspaces.core.executor.TaskRoutingProvider;
import org.springframework.dao.DataAccessException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author kimchy
 */
public class ExecutorMetaDataProvider {

    private Map<Class, Method> routingMethods = new ConcurrentHashMap<Class, Method>();

    private static Method NO_METHOD;

    static {
        try {
            NO_METHOD = Object.class.getMethod("toString");
        } catch (NoSuchMethodException e) {
            // won't happen
        }
    }

    public static Object extractRouting(Object task) {
        if (task instanceof TaskRoutingProvider) {
            return ((TaskRoutingProvider) task).getRouting();
        }
        Method method = findRoutingMethod(task);
        if (method == NO_METHOD) {
            return null;
        }
        try {
            return method.invoke(task);
        } catch (IllegalAccessException e) {
            throw new FailedToExecuteRoutingMethodException(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            throw new FailedToExecuteRoutingMethodException(e.getTargetException().getMessage(), e.getTargetException());
        }
    }

    public Object findRouting(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof TaskRoutingProvider) {
            return ((TaskRoutingProvider) obj).getRouting();
        }
        Method method = routingMethods.get(obj.getClass());
        if (method == null) {
            method = findRoutingMethod(obj);
            routingMethods.put(obj.getClass(), method);
        }
        if (method == NO_METHOD) {
            return null;
        }
        try {
            return method.invoke(obj);
        } catch (IllegalAccessException e) {
            throw new FailedToExecuteRoutingMethodException(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            throw new FailedToExecuteRoutingMethodException(e.getTargetException().getMessage(), e.getTargetException());
        }
    }

    public static class FailedToExecuteRoutingMethodException extends DataAccessException {

        public FailedToExecuteRoutingMethodException(String msg, Throwable cause) {
            super(msg, cause);
        }
    }

    private static Method findRoutingMethod(Object task) {
        Class targetClass = task.getClass();
        do {
            Method[] methods = targetClass.getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(SpaceRouting.class)) {
                    method.setAccessible(true);
                    return method;
                }
            }
            targetClass = targetClass.getSuperclass();
        } while (targetClass != null);
        return NO_METHOD;
    }
}

@@ -715,16 +715,101 @@
 outing;%0A
+import com.gigaspaces.reflect.IMethod;%0Aimport com.gigaspaces.reflect.ReflectionUtil;%0A
 import o
@@ -1069,16 +1069,128 @@
 p;%0A%0A/**%0A
+ * A helper class allowing to extract meta data related to executors/tasks (such as%0A * routing information).%0A *%0A
  * @auth
@@ -1263,24 +1263,25 @@
  Map%3CClass, 
+I
 Method%3E rout
@@ -1322,16 +1322,17 @@
 %3CClass, 
+I
 Method%3E(
@@ -1350,24 +1350,25 @@
 vate static 
+I
 Method NO_ME
@@ -1425,16 +1425,44 @@
 ETHOD = 
+ReflectionUtil.createMethod(
 Object.c
@@ -1487,16 +1487,17 @@
 String%22)
+)
 ;%0A      
@@ -1757,32 +1757,33 @@
       %7D%0A        
+I
 Method method = 
@@ -2474,24 +2474,25 @@
   %7D%0A        
+I
 Method metho
@@ -3351,16 +3351,17 @@
  static 
+I
 Method f
@@ -3704,22 +3704,51 @@
  return 
+ReflectionUtil.createMethod(
 method
+)
 ;%0A      

move routing method reflection to use fast reflection