All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.hasor.rsf.hprose.server.HproseService Maven / Gradle / Ivy

The newest version!
/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * HproseService.java                                     *
 *                                                        *
 * hprose service class for Java.                         *
 *                                                        *
 * LastModified: Oct 16, 2016                             *
 * Author: Ma Bingyao                   *
 *                                                        *
\**********************************************************/
package hprose.server;

import hprose.common.HandlerManager;
import hprose.common.HproseContext;
import hprose.common.HproseException;
import hprose.common.HproseFilter;
import hprose.common.HproseMethod;
import hprose.common.HproseMethods;
import hprose.common.HproseResultMode;
import hprose.io.ByteBufferStream;
import hprose.io.HproseMode;
import static hprose.io.HproseTags.TagArgument;
import static hprose.io.HproseTags.TagCall;
import static hprose.io.HproseTags.TagEnd;
import static hprose.io.HproseTags.TagError;
import static hprose.io.HproseTags.TagFunctions;
import static hprose.io.HproseTags.TagList;
import static hprose.io.HproseTags.TagOpenbrace;
import static hprose.io.HproseTags.TagResult;
import static hprose.io.HproseTags.TagTrue;
import hprose.io.serialize.Writer;
import hprose.io.unserialize.Reader;
import hprose.util.StrUtil;
import hprose.util.concurrent.Action;
import hprose.util.concurrent.AsyncFunc;
import hprose.util.concurrent.Call;
import hprose.util.concurrent.Func;
import hprose.util.concurrent.Promise;
import hprose.util.concurrent.Reducer;
import hprose.util.concurrent.Threads;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class HproseService extends HandlerManager implements HproseClients {

    private static volatile ScheduledExecutorService timerService = Executors.newSingleThreadScheduledExecutor();

    static {
        Threads.registerShutdownHandler(new Runnable() {
            public void run() {
                ScheduledExecutorService timer = timerService;
                timerService = Executors.newSingleThreadScheduledExecutor();
                timer.shutdownNow();
            }
        });
    }

    public HproseService() {
        add("call", new Callable() {
            public String call() throws Exception {
                return UUID.randomUUID().toString();
            }
        }, "#", true);
    }

    private final ArrayList filters = new ArrayList();
    private HproseMode mode = HproseMode.MemberMode;
    private boolean debugEnabled = false;
    private int errorDelay = 10000;
    protected HproseServiceEvent event = null;
    protected HproseMethods globalMethods = null;
    private final static ThreadLocal currentContext = new ThreadLocal();

    public static ServiceContext getCurrentContext() {
        return currentContext.get();
    }

    public HproseMethods getGlobalMethods() {
        if (globalMethods == null) {
            globalMethods = new HproseMethods();
        }
        return globalMethods;
    }

    public void setGlobalMethods(HproseMethods methods) {
        this.globalMethods = methods;
    }

    public final HproseMode getMode() {
        return mode;
    }

    public final void setMode(HproseMode mode) {
        this.mode = mode;
    }

    public final boolean isDebugEnabled() {
        return debugEnabled;
    }

    public final void setDebugEnabled(boolean enabled) {
        debugEnabled = enabled;
    }

    public int getErrorDelay() {
        return errorDelay;
    }

    public void setErrorDelay(int errorDelay) {
        this.errorDelay = errorDelay;
    }

    public final HproseServiceEvent getEvent() {
        return this.event;
    }

    public final void setEvent(HproseServiceEvent event) {
        this.event = event;
    }

    public final HproseFilter getFilter() {
        if (filters.isEmpty()) {
            return null;
        }
        return filters.get(0);
    }

    public final void setFilter(HproseFilter filter) {
        if (!filters.isEmpty()) {
            filters.clear();
        }
        if (filter != null) {
            filters.add(filter);
        }
    }

    public final HproseService addFilter(HproseFilter filter) {
        if (filter != null) {
            filters.add(filter);
        }
        return this;
    }

    public final boolean removeFilter(HproseFilter filter) {
        return filters.remove(filter);
    }

    public final HproseService add(Method method, Object obj, String aliasName) {
        getGlobalMethods().addMethod(method, obj, aliasName);
        return this;
    }

    public final HproseService add(Method method, Object obj, String aliasName, HproseResultMode mode) {
        getGlobalMethods().addMethod(method, obj, aliasName, mode);
        return this;
    }

    public final HproseService add(Method method, Object obj, String aliasName, boolean simple) {
        getGlobalMethods().addMethod(method, obj, aliasName, simple);
        return this;
    }

    public final HproseService add(Method method, Object obj, String aliasName, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(method, obj, aliasName, mode, simple);
        return this;
    }

    public final HproseService add(Method method, Object obj, String aliasName, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(method, obj, aliasName, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Method method, Object obj) {
        getGlobalMethods().addMethod(method, obj);
        return this;
    }

    public final HproseService add(Method method, Object obj, HproseResultMode mode) {
        getGlobalMethods().addMethod(method, obj, mode);
        return this;
    }

    public final HproseService add(Method method, Object obj, boolean simple) {
        getGlobalMethods().addMethod(method, obj, simple);
        return this;
    }

    public final HproseService add(Method method, Object obj, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(method, obj, mode, simple);
        return this;
    }

    public final HproseService add(Method method, Object obj, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(method, obj, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, String aliasName) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, aliasName);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, String aliasName, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, aliasName, mode);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, String aliasName, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, aliasName, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, String aliasName, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, aliasName, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, String aliasName, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, aliasName, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, String aliasName) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, aliasName);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, String aliasName, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, aliasName, mode);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, String aliasName, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, aliasName, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, String aliasName, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, aliasName, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, String aliasName, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, aliasName, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, mode);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, Class[] paramTypes, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, obj, paramTypes, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, mode);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, Class[] paramTypes, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMethod(methodName, type, paramTypes, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Object obj, String aliasName) {
        getGlobalMethods().addMethod(methodName, obj, aliasName);
        return this;
    }

    public final HproseService add(String methodName, Object obj, String aliasName, HproseResultMode mode) {
        getGlobalMethods().addMethod(methodName, obj, aliasName, mode);
        return this;
    }

    public final HproseService add(String methodName, Object obj, String aliasName, boolean simple) {
        getGlobalMethods().addMethod(methodName, obj, aliasName, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, String aliasName, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(methodName, obj, aliasName, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, String aliasName, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(methodName, obj, aliasName, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Class type, String aliasName) {
        getGlobalMethods().addMethod(methodName, type, aliasName);
        return this;
    }

    public final HproseService add(String methodName, Class type, String aliasName, HproseResultMode mode) {
        getGlobalMethods().addMethod(methodName, type, aliasName, mode);
        return this;
    }

    public final HproseService add(String methodName, Class type, String aliasName, boolean simple) {
        getGlobalMethods().addMethod(methodName, type, aliasName, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, String aliasName, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(methodName, type, aliasName, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, String aliasName, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(methodName, type, aliasName, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Object obj) {
        getGlobalMethods().addMethod(methodName, obj);
        return this;
    }

    public final HproseService add(String methodName, Object obj, HproseResultMode mode) {
        getGlobalMethods().addMethod(methodName, obj, mode);
        return this;
    }

    public final HproseService add(String methodName, Object obj, boolean simple) {
        getGlobalMethods().addMethod(methodName, obj, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(methodName, obj, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Object obj, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(methodName, obj, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String methodName, Class type) {
        getGlobalMethods().addMethod(methodName, type);
        return this;
    }

    public final HproseService add(String methodName, Class type, HproseResultMode mode) {
        getGlobalMethods().addMethod(methodName, type, mode);
        return this;
    }

    public final HproseService add(String methodName, Class type, boolean simple) {
        getGlobalMethods().addMethod(methodName, type, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethod(methodName, type, mode, simple);
        return this;
    }

    public final HproseService add(String methodName, Class type, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethod(methodName, type, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String[] aliasNames) {
        getGlobalMethods().addMethods(methodNames, obj, aliasNames);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String[] aliasNames, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, obj, aliasNames, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String[] aliasNames, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, aliasNames, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String[] aliasNames, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, aliasNames, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String[] aliasNames, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, obj, aliasNames, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String aliasPrefix) {
        getGlobalMethods().addMethods(methodNames, obj, aliasPrefix);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String aliasPrefix, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, obj, aliasPrefix, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String aliasPrefix, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, aliasPrefix, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String aliasPrefix, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, aliasPrefix, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, String aliasPrefix, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, obj, aliasPrefix, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj) {
        getGlobalMethods().addMethods(methodNames, obj);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, obj, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, obj, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Object obj, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, obj, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String[] aliasNames) {
        getGlobalMethods().addMethods(methodNames, type, aliasNames);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String[] aliasNames, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, type, aliasNames, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String[] aliasNames, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, aliasNames, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String[] aliasNames, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, aliasNames, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String[] aliasNames, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, type, aliasNames, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String aliasPrefix) {
        getGlobalMethods().addMethods(methodNames, type, aliasPrefix);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String aliasPrefix, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, type, aliasPrefix, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String aliasPrefix, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, aliasPrefix, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String aliasPrefix, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, aliasPrefix, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, String aliasPrefix, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, type, aliasPrefix, mode, simple, oneway);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type) {
        getGlobalMethods().addMethods(methodNames, type);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, HproseResultMode mode) {
        getGlobalMethods().addMethods(methodNames, type, mode);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addMethods(methodNames, type, mode, simple);
        return this;
    }

    public final HproseService add(String[] methodNames, Class type, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addMethods(methodNames, type, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Object obj, Class type, String aliasPrefix) {
        getGlobalMethods().addInstanceMethods(obj, type, aliasPrefix);
        return this;
    }

    public final HproseService add(Object obj, Class type, String aliasPrefix, HproseResultMode mode) {
        getGlobalMethods().addInstanceMethods(obj, type, aliasPrefix, mode);
        return this;
    }

    public final HproseService add(Object obj, Class type, String aliasPrefix, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, type, aliasPrefix, simple);
        return this;
    }

    public final HproseService add(Object obj, Class type, String aliasPrefix, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, type, aliasPrefix, mode, simple);
        return this;
    }

    public final HproseService add(Object obj, Class type, String aliasPrefix, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addInstanceMethods(obj, type, aliasPrefix, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Object obj, Class type) {
        getGlobalMethods().addInstanceMethods(obj, type);
        return this;
    }

    public final HproseService add(Object obj, Class type, HproseResultMode mode) {
        getGlobalMethods().addInstanceMethods(obj, type, mode);
        return this;
    }

    public final HproseService add(Object obj, Class type, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, type, simple);
        return this;
    }

    public final HproseService add(Object obj, Class type, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, type, mode, simple);
        return this;
    }

    public final HproseService add(Object obj, Class type, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addInstanceMethods(obj, type, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Object obj, String aliasPrefix) {
        getGlobalMethods().addInstanceMethods(obj, aliasPrefix);
        return this;
    }

    public final HproseService add(Object obj, String aliasPrefix, HproseResultMode mode) {
        getGlobalMethods().addInstanceMethods(obj, aliasPrefix, mode);
        return this;
    }

    public final HproseService add(Object obj, String aliasPrefix, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, aliasPrefix, simple);
        return this;
    }

    public final HproseService add(Object obj, String aliasPrefix, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, aliasPrefix, mode, simple);
        return this;
    }

    public final HproseService add(Object obj, String aliasPrefix, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addInstanceMethods(obj, aliasPrefix, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Object obj) {
        getGlobalMethods().addInstanceMethods(obj);
        return this;
    }

    public final HproseService add(Object obj, HproseResultMode mode) {
        getGlobalMethods().addInstanceMethods(obj, mode);
        return this;
    }

    public final HproseService add(Object obj, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, simple);
        return this;
    }

    public final HproseService add(Object obj, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addInstanceMethods(obj, mode, simple);
        return this;
    }

    public final HproseService add(Object obj, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addInstanceMethods(obj, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Class type, String aliasPrefix) {
        getGlobalMethods().addStaticMethods(type, aliasPrefix);
        return this;
    }

    public final HproseService add(Class type, String aliasPrefix, HproseResultMode mode) {
        getGlobalMethods().addStaticMethods(type, aliasPrefix, mode);
        return this;
    }

    public final HproseService add(Class type, String aliasPrefix, boolean simple) {
        getGlobalMethods().addStaticMethods(type, aliasPrefix, simple);
        return this;
    }

    public final HproseService add(Class type, String aliasPrefix, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addStaticMethods(type, aliasPrefix, mode, simple);
        return this;
    }

    public final HproseService add(Class type, String aliasPrefix, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addStaticMethods(type, aliasPrefix, mode, simple, oneway);
        return this;
    }

    public final HproseService add(Class type) {
        getGlobalMethods().addStaticMethods(type);
        return this;
    }

    public final HproseService add(Class type, HproseResultMode mode) {
        getGlobalMethods().addStaticMethods(type, mode);
        return this;
    }

    public final HproseService add(Class type, boolean simple) {
        getGlobalMethods().addStaticMethods(type, simple);
        return this;
    }

    public final HproseService add(Class type, HproseResultMode mode, boolean simple) {
        getGlobalMethods().addStaticMethods(type, mode, simple);
        return this;
    }

    public final HproseService add(Class type, HproseResultMode mode, boolean simple, boolean oneway) {
        getGlobalMethods().addStaticMethods(type, mode, simple, oneway);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Object obj) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, obj);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Object obj, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, obj, mode);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Object obj, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, obj, simple);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Object obj, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, obj, mode, simple);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Object obj, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, obj, mode, simple, oneway);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Class type) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, type);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Class type, HproseResultMode mode) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, type, mode);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Class type, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, type, simple);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Class type, HproseResultMode mode, boolean simple) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, type, mode, simple);
        return this;
    }

    public final HproseService addMissingMethod(String methodName, Class type, HproseResultMode mode, boolean simple, boolean oneway) throws NoSuchMethodException {
        getGlobalMethods().addMissingMethod(methodName, type, mode, simple, oneway);
        return this;
    }

    public final HproseService remove(String alias) {
        getGlobalMethods().remove(alias);
        return this;
    }

    private ByteBuffer outputFilter(ByteBuffer response, ServiceContext context) {
        if (response.position() != 0) {
            response.flip();
        }
        for (int i = 0, n = filters.size(); i < n; ++i) {
            response = filters.get(i).outputFilter(response, context);
            if (response.position() != 0) {
                response.flip();
            }
        }
        return response;
    }

    private ByteBuffer inputFilter(ByteBuffer request, ServiceContext context) {
        if (request.position() != 0) {
            request.flip();
        }
        for (int i = filters.size() - 1; i >= 0; --i) {
            request = filters.get(i).inputFilter(request, context);
            if (request.position() != 0) {
                request.flip();
            }
        }
        return request;
    }

    private String getErrorMessage(Throwable e) {
        if (debugEnabled) {
            StackTraceElement[] st = e.getStackTrace();
            StringBuffer es = new StringBuffer(e.toString()).append("\r\n");
            for (int i = 0, n = st.length; i < n; ++i) {
                es.append(st[i].toString()).append("\r\n");
            }
            return es.toString();
        }
        return e.toString();
    }

    private ByteBuffer sendError(Throwable e, ServiceContext context) {
        try {
            if (event != null) {
                Throwable ex = event.onSendError(e, context);
                if (ex != null) {
                    e = ex;
                }
            }
        }
        catch (Throwable ex) {
            e = ex;
        }
        try {
            ByteBufferStream data = new ByteBufferStream();
            Writer writer = new Writer(data.getOutputStream(), mode, true);
            data.write(TagError);
            writer.writeString(getErrorMessage(e));
            data.flip();
            return data.buffer;
        }
        catch (IOException ex) {
            fireErrorEvent(ex, context);
        }
        return null;
    }

    private ByteBuffer endError(Throwable e, ServiceContext context) {
        ByteBufferStream data = new ByteBufferStream();
        data.write(sendError(e, context));
        data.write(TagEnd);
        data.flip();
        return data.buffer;
    }

    protected Object[] fixArguments(Type[] argumentTypes, Object[] arguments, ServiceContext context) {
        int count = arguments.length;
        if (argumentTypes.length != count) {
            Object[] args = new Object[argumentTypes.length];
            System.arraycopy(arguments, 0, args, 0, count);
            Class argType = (Class) argumentTypes[count];
            if (argType.equals(HproseContext.class) || argType.equals(ServiceContext.class)) {
                args[count] = context;
            }
            return args;
        }
        return arguments;
    }

    private ByteBuffer doOutput(Object[] args, Object result, ServiceContext context) throws  IOException, InterruptedException, ExecutionException {
        ByteBufferStream data = new ByteBufferStream();
        HproseMethod remoteMethod = context.getRemoteMethod();
        if (result instanceof Future) {
            result = ((Future)result).get();
        }
        switch (remoteMethod.mode) {
            case RawWithEndTag:
                data.write((byte[])result);
                data.flip();
                return data.buffer;
            case Raw:
                data.write((byte[])result);
                break;
            default: {
                data.write(TagResult);
                boolean simple = remoteMethod.simple;
                Writer writer = new Writer(data.getOutputStream(), mode, simple);
                if (remoteMethod.mode == HproseResultMode.Serialized) {
                    data.write((byte[])result);
                }
                else {
                    writer.serialize(result);
                }
                if (context.isByref()) {
                    data.write(TagArgument);
                    writer.reset();
                    writer.writeArray(args);
                }
                break;
            }
        }
        data.flip();
        return data.buffer;
    }

    private Object beforeInvoke(final String name, final Object[] args, final ServiceContext context) {
        try {
            if (event != null) {
                event.onBeforeInvoke(name, args, context.isByref(), context);
            }
            return invokeHandler.handle(name, args, context).then(new Func() {
                public ByteBuffer call(Object result) throws Throwable {
                    if (result instanceof Throwable) {
                        throw (Throwable)result;
                    }
                    if (event != null) {
                        event.onAfterInvoke(name, args, context.isByref(), result, context);
                    }
                    return doOutput(args, result, context);
                }
            }).catchError(new Func() {
                public ByteBuffer call(Throwable e) throws Throwable {
                    return sendError(e, context);
                }
            });
        }
        catch (Throwable e) {
            return sendError(e, context);
        }
    }

    private Object callService(String name, Object[] args, ServiceContext context) throws Throwable {
        HproseMethod remoteMethod = context.getRemoteMethod();
        try {
            if (context.isMissingMethod()) {
                return remoteMethod.method.invoke(remoteMethod.obj, new Object[]{name, args});
            }
            else {
                Object[] arguments = fixArguments(remoteMethod.paramTypes, args, context);
                Object result = remoteMethod.method.invoke(remoteMethod.obj, arguments);
                if (context.isByref()) {
                    System.arraycopy(arguments, 0, args, 0, args.length);
                }
                return result;
            }
        }
        catch (Throwable ex) {
            Throwable e = ex.getCause();
            if (e != null) {
                throw e;
            }
            throw ex;
        }
    }

    @Override
    protected Promise invokeHandler(String name, Object[] args, HproseContext context) {
        return invokeHandler(name, args, (ServiceContext)context);
    }

    @Override
    protected Promise beforeFilterHandler(ByteBuffer request, HproseContext context) {
        return beforeFilter(request, (ServiceContext)context);
    }

    @Override
    protected Promise afterFilterHandler(ByteBuffer request, HproseContext context) {
        return afterFilter(request, (ServiceContext)context);
    }

    private Promise invokeHandler(final String name, final Object[] args, final ServiceContext context) {
        boolean oneway = context.getRemoteMethod().oneway;
        if (oneway) {
            timerService.execute(new Runnable() {
                public void run() {
                    try {
                        callService(name, args, context);
                    }
                    catch (Throwable e) {}
                }
            });
            return Promise.value(null);
        }
        return Promise.sync(new Call() {
            public Object call() throws Throwable {
                return callService(name, args, context);
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected Promise doInvoke(ByteBufferStream stream, ServiceContext context) throws IOException {
        HproseMethods methods = context.getMethods();
        Reader reader = new Reader(stream.getInputStream(), mode);
        ArrayList results = new ArrayList();
        int tag;
        do {
            reader.reset();
            String name = reader.readString();
            String aliasname = name.toLowerCase();
            HproseMethod remoteMethod = null;
            Object[] args;
            tag = reader.checkTags((char) TagList + "" +
                                   (char) TagEnd + "" +
                                   (char) TagCall);
            if (tag == TagList) {
                reader.reset();
                int count = reader.readInt(TagOpenbrace);
                if (methods != null) {
                    remoteMethod = methods.get(aliasname, count);
                }
                if (remoteMethod == null) {
                    remoteMethod = getGlobalMethods().get(aliasname, count);
                }
                if (remoteMethod == null) {
                    args = reader.readArray(count);
                }
                else {
                    args = new Object[count];
                    reader.readArray(remoteMethod.paramTypes, args, count);
                }
                tag = reader.checkTags((char) TagTrue + "" +
                                       (char) TagEnd + "" +
                                       (char) TagCall);
                if (tag == TagTrue) {
                    context.setByref(true);
                    tag = reader.checkTags((char) TagEnd + "" +
                                           (char) TagCall);
                }
            }
            else {
                if (methods != null) {
                    remoteMethod = methods.get(aliasname, 0);
                }
                if (remoteMethod == null) {
                    remoteMethod = getGlobalMethods().get(aliasname, 0);
                }
                args = new Object[0];
            }
            if (remoteMethod == null) {
                if (methods != null) {
                    remoteMethod = methods.get("*", 2);
                }
                if (remoteMethod == null) {
                    remoteMethod = getGlobalMethods().get("*", 2);
                }
                context.setMissingMethod(true);
            }
            else {
                context.setMissingMethod(false);
            }
            if (remoteMethod == null) {
                results.add(sendError(new NoSuchMethodError("Can't find this method " + name), context));
            }
            else {
                context.setRemoteMethod(remoteMethod);
                results.add(beforeInvoke(name, args, context));
            }
        } while (tag == TagCall);
        return Promise.reduce(results.toArray(),
            new Reducer() {
                public ByteBufferStream call(ByteBufferStream output, ByteBuffer result, int index) throws Throwable {
                    output.write(result);
                    return output;
                }
            },
            new ByteBufferStream()).then(new Func() {
                public ByteBuffer call(ByteBufferStream data) throws Throwable {
                    data.write(TagEnd);
                    return data.buffer;
                }
            }
        );
    }

    protected ByteBufferStream doFunctionList(ServiceContext context) throws IOException {
        HproseMethods methods = context.getMethods();
        ArrayList names = new ArrayList();
        names.addAll(getGlobalMethods().getAllNames());
        if (methods != null) {
            names.addAll(methods.getAllNames());
        }
        ByteBufferStream data = new ByteBufferStream();
        Writer writer = new Writer(data.getOutputStream(), mode, true);
        data.write(TagFunctions);
        writer.writeList(names);
        data.write(TagEnd);
        return data;
    }

    private Promise afterFilter(ByteBuffer request, ServiceContext context) {
        try {
            ByteBufferStream stream = new ByteBufferStream(request);
            switch (stream.read()) {
                case TagCall:
                    return doInvoke(stream, context);
                case TagEnd:
                    return Promise.value(doFunctionList(context).buffer);
                default:
                    throw new HproseException("Wrong Request: \r\n" + StrUtil.toString(stream));
            }
        }
        catch (IOException e) {
            return Promise.error(e);
        }
    }

    private Promise delayError(Throwable e, ServiceContext context) {
        ByteBuffer error = endError(e, context);
        if (errorDelay > 0) {
            return Promise.delayed(errorDelay, error);
        }
        else {
            return Promise.value(error);
        }
    }

    @SuppressWarnings("unchecked")
    private Promise beforeFilter(ByteBuffer request, final ServiceContext context) {
        Promise response;
        try {
            request = inputFilter(request, context);
            response = afterFilterHandler.handle(request, context).catchError(new AsyncFunc() {
                public Promise call(Throwable e) throws Throwable {
                    return delayError(e, context);
                }
            });
        }
        catch (Throwable e) {
            response = delayError(e, context);
        }
        return response.then(new Func() {
            public ByteBuffer call(ByteBuffer value) throws Throwable {
                return outputFilter(value, context);
            }
        });
    }

    protected void fireErrorEvent(Throwable e, ServiceContext context) {
        if (event != null) {
            event.onServerError(e, context);
        }
    }

    protected Promise handle(ByteBuffer buffer, ServiceContext context) {
        currentContext.set(context);
        return beforeFilterHandler.handle(buffer, context).whenComplete(new Runnable() {
            public void run() {
                currentContext.remove();
            }
        });
    }

    protected Promise handle(ByteBuffer buffer, HproseMethods methods, ServiceContext context) {
        context.setMethods(methods);
        return handle(buffer, context);
    }

    private int timeout = 120000;
    private int heartbeat = 3000;
    private PushEvent pushEvent = null;

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getHeartbeat() {
        return heartbeat;
    }

    public void setHeartbeat(int heartbeat) {
        this.heartbeat = heartbeat;
    }

    public PushEvent getPushEvent() {
        return pushEvent;
    }

    public void setPushEvent(PushEvent pushEvent) {
        this.pushEvent = pushEvent;
    }

    private final ConcurrentHashMap> allTopics = new ConcurrentHashMap>();

    private ConcurrentHashMap getTopics(String topic) {
        ConcurrentHashMap topics = allTopics.get(topic);
        if (topics == null) {
            throw new RuntimeException("topic \"" + topic + "\" is not published.");
        }
        return topics;
    }

    private void delTimer(ConcurrentHashMap topics, String id) {
        Topic t = topics.get(id);
        if (t != null && t.timer != null) {
            t.timer.cancel(false);
            t.timer = null;
        }
    }

    private void offline(ConcurrentHashMap topics, String topic, String id) {
        delTimer(topics, id);
        ConcurrentLinkedQueue messages = topics.remove(id).messages;
        for (Message message: messages) {
            message.detector.resolve(false);
        }
        if (pushEvent != null) {
            pushEvent.unsubscribe(topic, id, this);
        }
    }

    private void setTimer(final ConcurrentHashMap topics, final String topic, final String id) {
        Topic t = topics.get(id);
        if (t != null && t.timer == null) {
            t.timer = timerService.schedule(new Runnable() {
                public void run() {
                    offline(topics, topic, id);
                }
            }, t.heartbeat, TimeUnit.MILLISECONDS);
        }
    }

    private void resetTimer(final ConcurrentHashMap topics, final String topic, final String id) {
        delTimer(topics, id);
        setTimer(topics, topic, id);
    }

    private Promise setRequestTimer(final String topic, final String id, Promise request, int timeout) {
        final ConcurrentHashMap topics = getTopics(topic);
        if (timeout > 0) {
            return request.timeout(timeout).catchError(new AsyncFunc() {
                public Promise call(Throwable e) throws Throwable {
                    if (e instanceof TimeoutException) {
                        new Runnable() {
                            public void run() {
                                Topic t = topics.get(id);
                                t.timer = timerService.schedule(this, t.heartbeat, TimeUnit.MILLISECONDS);
                                if (t.count.get() < 0) {
                                    offline(topics, topic, id);
                                }
                                else {
                                    t.count.decrementAndGet();
                                }
                            }
                        }.run();
                    }
                    return null;
                }
            });
        }
        return request;
    }

    public final HproseService publish(String topic) {
        return publish(topic, -1, -1);
    }

    public final HproseService publish(String topic, int timeout) {
        return publish(topic, timeout, -1);
    }

    public final HproseService publish(final String topic, final int timeout, final int heartbeat) {
        final ConcurrentHashMap topics = new ConcurrentHashMap();
        allTopics.put(topic, topics);
        return add("call", new Func() {
            public Object call(final String id) throws Throwable {
                Topic t = topics.get(id);
                if (t != null) {
                    if (t.count.get() < 0) {
                        t.count.set(0);
                    }
                    ConcurrentLinkedQueue messages = t.messages;
                    if (messages.size() > 0) {
                        Message message = messages.poll();
                        message.detector.resolve(true);
                        resetTimer(topics, topic, id);
                        return message.result;
                    }
                    delTimer(topics, id);
                    t.count.incrementAndGet();
                    newRequest(t, id);
                }
                else {
                    t = new Topic((heartbeat < 0) ? HproseService.this.heartbeat : heartbeat);
                    topics.put(id, t);
                    newRequest(t, id);
                    if (pushEvent != null) {
                        pushEvent.subscribe(topic, id, HproseService.this);
                    }
                }
                return setRequestTimer(topic, id, t.request, (timeout < 0) ? HproseService.this.timeout : timeout);
            }

            private void newRequest(Topic t, final String id) {
                if (t.request != null) {
                    t.request.resolve(null);
                }
                Promise request = new Promise();
                request.complete(new Action() {
                    public void call(Object result) throws Throwable {
                        Topic t = topics.get(id);
                        t.count.decrementAndGet();
                    }
                });
                t.request = request;
            }
        }, topic);
    }

    public final HproseService publish(String[] topics) {
        return publish(topics, -1, -1);
    }

    public final HproseService publish(String[] topics, int timeout) {
        return publish(topics, timeout, -1);
    }

    public final HproseService publish(String[] topics, int timeout, int heartbeat) {
        for (int i = 0, n = topics.length; i < n; ++i) {
            publish(topics[i], timeout, heartbeat);
        }
        return this;
    }

    public final String[] idlist(String topic) {
        return getTopics(topic).keySet().toArray(new String[0]);
    }

    public final boolean exist(String topic, String id) {
        return getTopics(topic).containsKey(id);
    }

    public final void broadcast(String topic, Object result) {
        multicast(topic, idlist(topic), result);
    }

    public final void broadcast(String topic, Object result, Action callback) {
        multicast(topic, idlist(topic), result, callback);
    }

    public final void multicast(String topic, String[] ids, Object result) {
        for (int i = 0, n = ids.length; i < n; ++i) {
            push(topic, ids[i], result);
        }
    }

    public final void multicast(String topic, String[] ids, Object result, Action callback) {
        if (callback == null) {
            multicast(topic, ids, result);
            return;
        }
        int n = ids.length;
        List sent = Collections.synchronizedList(new ArrayList(n));
        AtomicInteger count = new AtomicInteger(n);
        for (int i = 0; i < n; ++i) {
            String id = ids[i];
            if (id != null) {
                push(topic, id, result).then(check(sent, id, count, callback));
            }
            else {
                count.decrementAndGet();
            }
        }
    }

    private Action check(final List sent, final String id, final AtomicInteger count, final Action callback) {
        return new Action() {
            public void call(Boolean success) throws Throwable {
                if (success) {
                    sent.add(id);
                }
                if (count.decrementAndGet() == 0) {
                    callback.call(sent.toArray(new String[sent.size()]));
                }
            }
        };
    }

    public final void unicast(String topic, String id, Object result) {
        push(topic, id, result);
    }

    public final void unicast(String topic, String id, Object result, Action callback) {
        Promise detector = push(topic, id, result);
        if (callback != null) {
            detector.then(callback);
        }
    }

    public final Promise push(String topic, Object result) {
        return push(topic, idlist(topic), result);
    }

    public final Promise push(String topic, String[] ids, Object result) {
        final Promise detector = new Promise();
        multicast(topic, ids, result, new Action() {
            public void call(String[] value) throws Throwable {
                detector.resolve(value);
            }
        });
        return detector;
    }

    public final Promise push(final String topic, final String id, Object result) {
        if (Promise.isThenable(result)) {
            AsyncFunc callback = new AsyncFunc() {
                public Promise call(Object value) throws Throwable {
                    return push(topic, id, value);
                }
            };
            return Promise.toPromise(result).complete(callback);
        }
        final ConcurrentHashMap topics = getTopics(topic);
        Topic t = topics.get(id);
        if (t == null) {
            return Promise.value(false);
        }
        if (t.request != null) {
            try {
                t.request.resolve(result);
                t.request = null;
                setTimer(topics, topic, id);
                return Promise.value(true);
            }
            catch (NullPointerException e) {}
        }
        Promise detector = new Promise();
        t.messages.add(new Message(detector, result));
        setTimer(topics, topic, id);
        return detector;
    }

}