Package org.auraframework.impl.java.controller

Source Code of org.auraframework.impl.java.controller.JavaControllerDefFactory

/*
* Copyright (C) 2013 salesforce.com, inc.
*
* 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.auraframework.impl.java.controller;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.auraframework.builder.DefBuilder;
import org.auraframework.def.ActionDef;
import org.auraframework.def.ControllerDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.TypeDef;
import org.auraframework.def.ValueDef;
import org.auraframework.impl.java.BaseJavaDefFactory;
import org.auraframework.impl.java.model.JavaValueDef;
import org.auraframework.impl.java.type.JavaTypeDef;
import org.auraframework.impl.system.DefDescriptorImpl;
import org.auraframework.impl.system.SubDefDescriptorImpl;
import org.auraframework.system.Annotations.AuraEnabled;
import org.auraframework.system.Annotations.BackgroundAction;
import org.auraframework.system.Annotations.CabooseAction;
import org.auraframework.system.Annotations.Controller;
import org.auraframework.system.Annotations.Key;
import org.auraframework.system.DefFactory;
import org.auraframework.system.Location;
import org.auraframework.system.SourceLoader;
import org.auraframework.throwable.quickfix.InvalidDefinitionException;
import org.auraframework.throwable.quickfix.QuickFixException;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
* A {@link DefFactory} for Java controllers.
*/
public class JavaControllerDefFactory extends BaseJavaDefFactory<ControllerDef> {

    public JavaControllerDefFactory() {
        this(null);
    }

    public JavaControllerDefFactory(List<SourceLoader> sourceLoaders) {
        super(sourceLoaders);
    }

    @Override
    protected DefBuilder<?, ? extends ControllerDef> getBuilder(DefDescriptor<ControllerDef> descriptor)
            throws QuickFixException {
        JavaControllerDefImpl.Builder builder = new JavaControllerDefImpl.Builder();
        builder.setDescriptor(descriptor);

        Class<?> c = getClazz(descriptor);
        if (c == null) {
            return null;
        }
        builder.setControllerClass(c);
        // FIXME = "we need an md5";
        builder.setLocation(c.getCanonicalName(), -1);
        Controller ann = c.getAnnotation(Controller.class);
        if (ann == null) {
            throw new InvalidDefinitionException(String.format(
                    "@Controller annotation is required on all Controllers.  Not found on %s", descriptor),
                    builder.getLocation());
        }
        builder.setBean(ann.bean());
        try {
            builder.setActionMap(createActions(c, builder.getDescriptor(), ann.bean()));
        } catch (QuickFixException qfe) {
            builder.setParseError(qfe);
        }
        return builder;
    }

    private static String formatType(Type t) {
        Class<?> clazz = JavaTypeDef.getClass(t);
        String result;
      
        if (clazz != null) {
            result = clazz.getName();
        } else {
            result = "Object";
        }

        if (t instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) t;
            if (pt.getActualTypeArguments().length > 0) {
                result += "<";
                boolean first = true;
                for (Type tp : pt.getActualTypeArguments()) {
                    if (!first) {
                        result += ",";
                    }
                    first = false;
                    if (tp == null) {
                        result += "Object";
                    } else {
                        result += formatType(tp); // recurse if nested parameterized
                    }
                }
                result += ">";
            }
        }
        return result;
    }

    /**
     * Add a single method as an action.
     *
     * @param method the method for which we want to create an action.
     * @throws QuickFixException if the method is invalid for some reason.
     */
    private static JavaActionDef makeActionDef(Method method, Class<?> controllerClass,
            DefDescriptor<ControllerDef> controllerDesc) throws QuickFixException {

        JavaActionDef.Builder actionBuilder = new JavaActionDef.Builder();
        String name = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();
        List<ValueDef> params = Lists.newArrayList();
        List<String> loggableParams = Lists.newArrayList();
        Annotation[][] paramAnnotations = method.getParameterAnnotations();

        actionBuilder.setDescriptor(SubDefDescriptorImpl.getInstance(name, controllerDesc, ActionDef.class));
        actionBuilder.setMethod(method);
        actionBuilder.setReturnTypeDescriptor(DefDescriptorImpl.getInstance("java://"
                + method.getReturnType().getName(), TypeDef.class));
        actionBuilder.setJavaParams(method.getParameterTypes());
        Type[] genParams = method.getGenericParameterTypes();

        for (int i = 0; i < paramTypes.length; i++) {
            boolean found = false;
            for (Annotation annotation : paramAnnotations[i]) {
                if (annotation instanceof Key) {
                    found = true;
                    String qn = "java://" + formatType(genParams[i]);
                    DefDescriptor<TypeDef> typeDefDesc = DefDescriptorImpl.getInstance(qn, TypeDef.class);

                    // FIXME = "we need an md5";
                    String paramName = ((Key) annotation).value();
                    ValueDef valueDef = new JavaValueDef(paramName, typeDefDesc, new Location(
                            controllerClass.getName() + "." + name, 0));
                    params.add(valueDef);
                   
                    if (((Key)annotation).loggable()) {
                        loggableParams.add(paramName);
                    }
                }
            }
            if (!found) {
                throw new InvalidDefinitionException("@Key annotation is required on all action parameters",
                        new Location(controllerClass.getName() + "." + name, 0));
            }
        }
        actionBuilder.setParams(params);
        actionBuilder.setLoggableParams(loggableParams);
       
      actionBuilder.setBackground(method.isAnnotationPresent(BackgroundAction.class));
      actionBuilder.setCaboose(method.isAnnotationPresent(CabooseAction.class));
       
        return actionBuilder.build();
    }

    private static void throwControllerError(String message, Class<?> clazz, Method method) throws QuickFixException {
        throw new InvalidDefinitionException(message + method.getName(),
                new Location("java://"+clazz.getCanonicalName(), 0));
    }

    /**
     * Create actions for all aura enabled actions on a class.
     *
     * Note that this function will not look at any method that is not public.
     * If we want to check for @AuraEnabled methods that are marked non-public
     * we would need to walk every method in the heirarchy, checking for that
     * case. It would really just be for validation.
     *
     * @param controllerClass the class that contains our action functions.
     * @param controllerDesc a descriptor for the class.
     */
    public static Map<String, JavaActionDef> createActions(Class<?> controllerClass,
            DefDescriptor<ControllerDef> controllerDesc, boolean bean) throws QuickFixException {
        Map<String, JavaActionDef> actions = Maps.newTreeMap();
        for (Method method : controllerClass.getMethods()) {
            if (method.isAnnotationPresent(AuraEnabled.class)) {
                int modifiers = method.getModifiers();

                if (!Modifier.isPublic(modifiers)) {
                    throwControllerError("Invalid non-public action: ", controllerClass, method);
                }
                if (bean) {
                    if (Modifier.isStatic(modifiers)) {
                        throwControllerError("Invalid static action in a bean: ", controllerClass, method);
                    }
                } else {
                    if (!Modifier.isStatic(modifiers)) {
                        throwControllerError("Invalid non-static action in a controller: ", controllerClass, method);
                    }
                }
                JavaActionDef action = makeActionDef(method, controllerClass, controllerDesc);

                if (action != null) {
                    // this line disallows action overloading. dunno if we care.
                    if (actions.containsKey(action.getName())) {
                        throw new InvalidDefinitionException("Duplicate action " + action.getName(), new Location(
                                controllerClass.getName(), 0));
                    }
                    actions.put(action.getName(), action);
                }
            }
        }
        return actions;
    }
}
TOP

Related Classes of org.auraframework.impl.java.controller.JavaControllerDefFactory

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.