Package org.atmosphere.wasync.transport

Source Code of org.atmosphere.wasync.transport.TransportsUtil

/*
* Copyright 2014 Jeanfrancois Arcand
*
* 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.atmosphere.wasync.transport;

import org.atmosphere.wasync.Decoder;
import org.atmosphere.wasync.Event;
import org.atmosphere.wasync.Function;
import org.atmosphere.wasync.FunctionResolver;
import org.atmosphere.wasync.FunctionWrapper;
import org.atmosphere.wasync.ReplayDecoder;
import org.atmosphere.wasync.util.TypeResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class TransportsUtil {

    private final static Logger logger = LoggerFactory.getLogger(TransportsUtil.class);

    public static boolean invokeFunction(List<Decoder<? extends Object, ?>> decoders,
                                         List<FunctionWrapper> functions,
                                         Class<?> implementedType,
                                         Object instanceType,
                                         String functionName,
                                         FunctionResolver resolver) {
        return invokeFunction(Event.MESSAGE, decoders, functions, implementedType, instanceType, functionName, resolver);
    }

    public static boolean invokeFunction(Event e,
                                         List<Decoder<? extends Object, ?>> decoders,
                                         List<FunctionWrapper> functions,
                                         Class<?> implementedType,
                                         Object instanceType,
                                         String functionName,
                                         FunctionResolver resolver) {
        boolean hasMatch = false;
        String originalMessage = instanceType == null ? "" : instanceType.toString();

        List<Object> decodedObjects = new CopyOnWriteArrayList<Object>();
        if (instanceType != null) {
            decodedObjects = matchDecoder(e, instanceType, decoders, decodedObjects);
        }

        for (FunctionWrapper wrapper : functions) {
            Function f = wrapper.function();
            Class<?>[] typeArguments = TypeResolver.resolveArguments(f.getClass(), Function.class);

            if (typeArguments == null) {
                logger.trace("Lambda function should not be used. Inferring type as String.class");
                typeArguments = new Class[]{String.class};
            }

            if (typeArguments.length > 0 && instanceType != null) {
                boolean b = false;
                if (decodedObjects.isEmpty()) {
                    implementedType = instanceType.getClass();
                    b = matchFunction(instanceType, typeArguments, implementedType, resolver, originalMessage, functionName, wrapper, f);
                } else {
                    for (Object o : decodedObjects) {
                        if (!Decoder.Decoded.class.isAssignableFrom(o.getClass())) {
                            b = matchFunction(o, typeArguments, o.getClass(), resolver, originalMessage, functionName, wrapper, f);
                        }
                    }
                }
                if (b) hasMatch = true;
            }
        }

        if (!hasMatch && !e.equals(Event.MESSAGE)) {
            // Since we have no match, most probably because a decoder isn't matching a function or the Event's type, try
            // to match Event type directly with a String.
            // This can happens if a decoder is not behaving properly.
            // instanceType != null because a ReplayDecoder may have interrupted
            for (FunctionWrapper wrapper : functions) {
                Function f = wrapper.function();
                if (wrapper.functionName().equalsIgnoreCase(functionName)) {
                    hasMatch = true;
                    logger.trace("{} .on {}", functionName, instanceType);
                    f.on(originalMessage);
                }
            }
        }

        return hasMatch;
    }

    public static boolean matchFunction(Object instanceType,
                                        Class[] typeArguments,
                                        Class<?> implementedType,
                                        FunctionResolver resolver,
                                        String originalMessage,
                                        Object functionName,
                                        FunctionWrapper wrapper,
                                        Function f) {
        boolean hasMatch = false;
        if (instanceType != null && typeArguments.length > 0 && typeArguments[0].isAssignableFrom(implementedType)) {
            if (resolver.resolve(originalMessage, functionName, wrapper)) {
                hasMatch = true;
                logger.trace("{} .on {}", functionName, instanceType);
                try {
                    f.on(instanceType);
                } catch (Exception e) {
                    logger.warn("Function {} thrown an exception", functionName, e);
                }
            }
        }
        return hasMatch;
    }

    public static List<Object> matchDecoder(Event e, Object instanceType, List<Decoder<? extends Object, ?>> decoders, List<Object> decodedObjects) {
        for (Decoder d : decoders) {
            Class<?>[] typeArguments = TypeResolver.resolveArguments(d.getClass(), Decoder.class);
            if (instanceType != null && typeArguments.length > 0 && typeArguments[0].isAssignableFrom(instanceType.getClass())) {
                boolean replay = ReplayDecoder.class.isAssignableFrom(d.getClass());

                logger.trace("{} is trying to decode {}", d, instanceType);
                Object decoded = null;

                try {
                    decoded = d.decode(e, instanceType);
                } catch (Exception ex) {
                    logger.warn("Decoder exception", ex);
                }

                if (decoded != null && Decoder.Decoded.class.isAssignableFrom(decoded.getClass())) {
                    Decoder.Decoded<?> o = Decoder.Decoded.class.cast(decoded);
                    // The object has been decoded and doesn't need to be dispatched.
                    if (o.action().equals(Decoder.Decoded.ACTION.ABORT)) {
                        logger.trace("Decoder {} fully decoded {}", d, instanceType);
                        decodedObjects.add(o);
                        break;
                    } else {
                        decoded = o.decoded();
                    }
                }

                // The decoded message is a list, so we re-inject.
                if (replay && decoded != null && List.class.isAssignableFrom(decoded.getClass())) {
                    List<Object> l = List.class.cast(decoded);
                    if (l.isEmpty()) {
                        continue;
                    }
                    List<Decoder<? extends Object, ?>> nd = new ArrayList<Decoder<? extends Object, ?>>();
                    boolean add = false;
                    for (Decoder d2 : decoders) {
                        if (d2.equals(d)) {
                            add = true;
                            continue;
                        }

                        if (add) nd.add(d2);
                    }

                    // If no decoder found
                    if (nd.isEmpty()) {
                        return l;
                    }

                    for (Object m : l) {
                        return matchDecoder(e, m, nd, decodedObjects);
                    }
                } else if (decoded != null) {
                    logger.trace("Decoder {} match {}", d, instanceType);
                    decodedObjects.add(decoded);
                }
            }
        }
        return decodedObjects;
    }

}
TOP

Related Classes of org.atmosphere.wasync.transport.TransportsUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.