org.red5.server.service.ServiceInvoker.java Source code

Java tutorial

Introduction

Here is the source code for org.red5.server.service.ServiceInvoker.java

Source

package org.red5.server.service;

/*
 * RED5 Open Source Flash Server - http://www.osflash.org/red5
 * 
 * Copyright (c) 2006-2007 by respective authors (see below). All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License as published by the Free Software 
 * Foundation; either version 2.1 of the License, or (at your option) any later 
 * version. 
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along 
 * with this library; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.Red5;
import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IServiceCall;
import org.red5.server.api.service.IServiceInvoker;

/**
 * Makes remote calls, invoking services, resolves service handlers
 *
 * @author The Red5 Project (red5@osflash.org)
 * @author Luke Hubbard, Codegent Ltd (luke@codegent.com)
 */
public class ServiceInvoker implements IServiceInvoker {

    /**
     * Logger
     */
    private static final Log log = LogFactory.getLog(ServiceInvoker.class);

    /**
     * Service name
     */
    public static final String SERVICE_NAME = "serviceInvoker";

    /**
     * Service resolvers set
     */
    private Set<IServiceResolver> serviceResolvers = new HashSet<IServiceResolver>();

    /**
      * Setter for service resolvers.
      *
      * @param resolvers  Service resolvers
      */
    public void setServiceResolvers(Set<IServiceResolver> resolvers) {
        serviceResolvers = resolvers;
    }

    /**
     * Lookup a handler for the passed service name in the given scope.
     * 
     * @param scope              Scope
     * @param serviceName        Service name
     * @return                   Service handler
     */
    private Object getServiceHandler(IScope scope, String serviceName) {
        // Get application scope handler first
        Object service = scope.getHandler();
        if (serviceName == null || serviceName.equals("")) {
            // No service requested, return application scope handler
            return service;
        }

        // Search service resolver that knows about service name
        for (IServiceResolver resolver : serviceResolvers) {
            service = resolver.resolveService(scope, serviceName);
            if (service != null) {
                return service;
            }
        }

        // Requested service does not exist.
        return null;
    }

    /** {@inheritDoc} */
    public boolean invoke(IServiceCall call, IScope scope) {
        String serviceName = call.getServiceName();
        if (log.isDebugEnabled()) {
            log.debug("Service name " + serviceName);
        }
        Object service = getServiceHandler(scope, serviceName);
        if (service == null) {
            // Exception must be thrown if service was not found
            call.setException(new ServiceNotFoundException(serviceName));
            // Set call status
            call.setStatus(Call.STATUS_SERVICE_NOT_FOUND);
            log.warn("Service not found: " + serviceName);
            return false;
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Service found: " + serviceName);
            }
        }
        // Invoke if everything is ok
        return invoke(call, service);
    }

    /** {@inheritDoc} */
    public boolean invoke(IServiceCall call, Object service) {
        IConnection conn = Red5.getConnectionLocal();
        String methodName = call.getServiceMethodName();

        Object[] args = call.getArguments();
        Object[] argsWithConnection;
        if (args != null) {
            argsWithConnection = new Object[args.length + 1];
            argsWithConnection[0] = conn;
            for (int i = 0; i < args.length; i++) {
                if (log.isDebugEnabled()) {
                    log.debug("   " + i + " => " + args[i]);
                }
                argsWithConnection[i + 1] = args[i];
            }
        } else {
            argsWithConnection = new Object[] { conn };
        }

        Object[] methodResult = null;
        // First, search for method with the connection as first parameter.
        methodResult = ServiceUtils.findMethodWithExactParameters(service, methodName, argsWithConnection);
        if (methodResult.length == 0 || methodResult[0] == null) {
            // Second, search for method without the connection as first
            // parameter.
            methodResult = ServiceUtils.findMethodWithExactParameters(service, methodName, args);
            if (methodResult.length == 0 || methodResult[0] == null) {
                // Third, search for method with the connection as first
                // parameter in a list argument.
                methodResult = ServiceUtils.findMethodWithListParameters(service, methodName, argsWithConnection);
                if (methodResult.length == 0 || methodResult[0] == null) {
                    // Fourth, search for method without the connection as first
                    // parameter in a list argument.
                    methodResult = ServiceUtils.findMethodWithListParameters(service, methodName, args);
                    if (methodResult.length == 0 || methodResult[0] == null) {
                        log.error("Method " + methodName + " not found in " + service);
                        call.setStatus(Call.STATUS_METHOD_NOT_FOUND);
                        call.setException(new MethodNotFoundException(methodName));
                        return false;
                    }
                }
            }
        }

        Object result = null;
        Method method = (Method) methodResult[0];
        Object[] params = (Object[]) methodResult[1];

        try {
            if (log.isDebugEnabled()) {
                log.debug("Invoking method: " + method.toString());
            }
            if (method.getReturnType() == Void.class) {
                method.invoke(service, params);
                call.setStatus(Call.STATUS_SUCCESS_VOID);
            } else {
                result = method.invoke(service, params);
                if (log.isDebugEnabled()) {
                    log.debug("result: " + result);
                }
                call.setStatus(result == null ? Call.STATUS_SUCCESS_NULL : Call.STATUS_SUCCESS_RESULT);
            }
            if (call instanceof IPendingServiceCall) {
                ((IPendingServiceCall) call).setResult(result);
            }
        } catch (IllegalAccessException accessEx) {
            call.setException(accessEx);
            call.setStatus(Call.STATUS_ACCESS_DENIED);
            log.error("Error executing call: " + call);
            log.error("Service invocation error", accessEx);
            return false;
        } catch (InvocationTargetException invocationEx) {
            call.setException(invocationEx);
            call.setStatus(Call.STATUS_INVOCATION_EXCEPTION);
            log.error("Error executing call: " + call);
            log.error("Service invocation error", invocationEx);
            return false;
        } catch (Exception ex) {
            call.setException(ex);
            call.setStatus(Call.STATUS_GENERAL_EXCEPTION);
            log.error("Error executing call: " + call);
            log.error("Service invocation error", ex);
            return false;
        }
        return true;
    }

}