com.zenesis.qx.remote.ProxyMethod.java Source code

Java tutorial

Introduction

Here is the source code for com.zenesis.qx.remote.ProxyMethod.java

Source

/**
 * ************************************************************************
 * 
 *    server-objects - a contrib to the Qooxdoo project that makes server 
 *    and client objects operate seamlessly; like Qooxdoo, server objects 
 *    have properties, events, and methods all of which can be access from
 *    either server or client, regardless of where the original object was
 *    created.
 * 
 *    http://qooxdoo.org
 * 
 *    Copyright:
 *      2010 Zenesis Limited, http://www.zenesis.com
 * 
 *    License:
 *      LGPL: http://www.gnu.org/licenses/lgpl.html
 *      EPL: http://www.eclipse.org/org/documents/epl-v10.php
 *      
 *      This software is provided under the same licensing terms as Qooxdoo,
 *      please see the LICENSE file in the Qooxdoo project's top-level directory 
 *      for details.
 * 
 *    Authors:
 *      * John Spackman (john.spackman@zenesis.com)
 * 
 * ************************************************************************
 */
package com.zenesis.qx.remote;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.io.IOException;
import java.util.Comparator;
import java.util.Map;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.zenesis.qx.remote.annotations.Remote;

/**
 * ProxyMethod is compiled by ProxyManager and attached to ProxyType to define
 * a method that is proxied.
 * 
 * @author John Spackman
 *
 */
public class ProxyMethod implements JsonSerializable {

    private static final Logger log = Logger.getLogger(ProxyMethod.class);

    public static final Comparator<ProxyMethod> ALPHA_COMPARATOR = new Comparator<ProxyMethod>() {

        /* (non-Javadoc)
         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
         */
        @Override
        public int compare(ProxyMethod o1, ProxyMethod o2) {
            return o1.getName().compareTo(o2.getName());
        }
    };

    private final Method method;
    private final Remote.Array array;
    private final boolean isMap;
    @SuppressWarnings("unused")
    private final Class keyType;
    private final Class arrayType;
    private final boolean prefetchResult;
    private final boolean cacheResult;
    private final boolean staticMethod;

    /**
     * @param name
     * @param returnType
     * @param parameters
     */
    public ProxyMethod(Method method) {
        super();
        this.method = method;

        Class returnType = method.getReturnType();
        Class keyType = String.class;
        boolean prefetchResult = false;
        boolean cacheResult = false;
        isMap = Map.class.isAssignableFrom(returnType);
        com.zenesis.qx.remote.annotations.Method anno = method
                .getAnnotation(com.zenesis.qx.remote.annotations.Method.class);

        if (returnType.isArray() || Iterable.class.isAssignableFrom(returnType) || isMap) {
            // How to present on the client - only ArrayList by default is wrapped on the client
            Remote.Array array;
            if (returnType.isArray()) {
                returnType = returnType.getComponentType();
                array = Remote.Array.NATIVE;
            } else {
                returnType = Object.class;
                array = Remote.Array.WRAP;
            }

            // Component type
            if (anno != null) {
                if (anno.array() != Remote.Array.DEFAULT)
                    array = anno.array();
                if (anno.arrayType() != Object.class)
                    returnType = anno.arrayType();
                if (anno.keyType() != Object.class)
                    keyType = anno.keyType();
            }
            this.array = array;
            this.arrayType = returnType;
        } else {
            array = null;
            this.arrayType = null;
        }

        if (anno != null) {
            if (method.getParameterTypes().length == 0) {
                prefetchResult = anno.prefetchResult();
                cacheResult = anno.cacheResult() || prefetchResult;
            }
        }

        this.keyType = keyType;
        this.prefetchResult = prefetchResult;
        this.staticMethod = (method.getModifiers() & Modifier.STATIC) != 0;
        if (staticMethod && cacheResult) {
            log.warn("Cannot cacheResult on static method " + method);
            cacheResult = false;
        }
        this.cacheResult = cacheResult;
    }

    /* (non-Javadoc)
     * @see org.codehaus.jackson.map.JsonSerializable#serialize(org.codehaus.jackson.JsonGenerator, org.codehaus.jackson.map.SerializerProvider)
     */
    @Override
    public void serialize(JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException {
        jgen.writeStartObject();

        // Write the return type
        Class clazz = arrayType != null ? arrayType : method.getReturnType();
        if (Proxied.class.isAssignableFrom(clazz)) {
            ProxyType type = ProxyTypeManager.INSTANCE.getProxyType(clazz);
            jgen.writeObjectField("returnType", type);
        } else if (isMap) {
            jgen.writeBooleanField("map", true);
        }
        if (cacheResult)
            jgen.writeBooleanField("cacheResult", true);
        if (staticMethod)
            jgen.writeBooleanField("staticMethod", true);

        // Whether to wrap the return
        if (array != null)
            jgen.writeObjectField("returnArray", array.toString().toLowerCase());

        // The parameters - if any are Proxied objects, we need to write their class
        Class[] parameters = method.getParameterTypes();
        if (parameters.length > 0) {
            jgen.writeArrayFieldStart("parameters");
            for (int i = 0; i < parameters.length; i++) {
                if (Proxied.class.isAssignableFrom(parameters[i]))
                    jgen.writeObject(ProxyTypeManager.INSTANCE.getProxyType(parameters[i]));
                else
                    jgen.writeNull();
            }
            jgen.writeEndArray();
        }

        jgen.writeEndObject();
    }

    /* (non-Javadoc)
     * @see com.fasterxml.jackson.databind.JsonSerializable#serializeWithType(com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider, com.fasterxml.jackson.databind.jsontype.TypeSerializer)
     */
    @Override
    public void serializeWithType(JsonGenerator gen, SerializerProvider sp, TypeSerializer ts)
            throws IOException, JsonProcessingException {
        serialize(gen, sp);
    }

    /**
     * Gets the prefetch value
     * @param self
     * @return
     */
    public Object getPrefetchValue(Object self) {
        try {
            return method.invoke(self);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException(
                    "Error while invoking " + method + " on " + self + ": " + e.getCause().getMessage(),
                    e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(
                    "Error while invoking " + method + " on " + self + ": " + e.getMessage(), e);
        }
    }

    /**
     * @return the name
     */
    public String getName() {
        return method.getName();
    }

    /**
     * @return the method
     */
    public Method getMethod() {
        return method;
    }

    /**
     * @return the prefetchResult
     */
    public boolean isPrefetchResult() {
        return prefetchResult;
    }

    /**
     * @return the cacheResult
     */
    public boolean isCacheResult() {
        return cacheResult;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return method.toString();
    }

}