de.openknowledge.extensions.jsf.model.ModelMethod.java Source code

Java tutorial

Introduction

Here is the source code for de.openknowledge.extensions.jsf.model.ModelMethod.java

Source

/*
 * Copyright 2013 Arne Limburg
 *
 * 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 de.openknowledge.extensions.jsf.model;

import static org.apache.commons.lang3.Validate.notNull;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;

import de.openknowledge.extensions.el.SimpleMethodExpression;
import de.openknowledge.extensions.el.SimpleMethodExpressionParser;

/**
 * @author Arne Limburg - open knowledge GmbH
 */
@FacesComponent(ModelMethod.COMPONENT_TYPE)
public class ModelMethod extends UIInput {

    public static final String COMPONENT_TYPE = "de.openknowledge.ModelMethod";

    public ModelMethod() {
        setRendererType("de.openknowledge.EmtpyRenderer");
    }

    @Override
    public void validate(FacesContext context) {
    }

    @Override
    public void updateModel(FacesContext context) {
        ValueExpression expression = getValueExpression("value");
        SimpleMethodExpressionParser parser = new SimpleMethodExpressionParser(expression.getExpressionString());
        SimpleMethodExpression methodExpression = parser.parse();
        ExpressionFactory expressionFactory = notNull(context, "context may not be null").getApplication()
                .getExpressionFactory();
        ValueExpression baseExpression = expressionFactory.createValueExpression(context.getELContext(),
                "#{" + methodExpression.getBase() + '}', Object.class);
        Object baseValue = baseExpression.getValue(context.getELContext());
        Class<? extends Object> baseType = baseValue.getClass();
        UIInput[] parameterComponents = findComponents(methodExpression);
        Class<?>[] parameterTypes = findParameterTypes(context, methodExpression, expressionFactory,
                parameterComponents);
        Method method = findMethod(baseType, methodExpression.getMethodName(), parameterTypes);
        Object[] parameters = findParameters(context, methodExpression, expressionFactory, parameterComponents,
                parameterTypes);
        try {
            method.invoke(baseValue, parameters);
        } catch (InvocationTargetException e) {
            throw new ELException(e.getTargetException());
        } catch (Exception e) {
            throw new ELException(e);
        }
    }

    private Object[] findParameters(FacesContext context, SimpleMethodExpression methodExpression,
            ExpressionFactory expressionFactory, UIInput[] parameterComponents, Class<?>[] parameterTypes) {
        Object[] parameters = new Object[parameterTypes.length];
        for (int i = 0; i < parameterTypes.length; i++) {
            if (parameterComponents[i] != null) {
                parameters[i] = parameterComponents[i].getSubmittedValue();
                if (parameters[i] == null) {
                    parameters[i] = parameterComponents[i].getValue();
                }
            } else {
                parameters[i] = expressionFactory
                        .createValueExpression(methodExpression.getParameters()[i], Object.class)
                        .getValue(context.getELContext());
            }
        }
        return parameters;
    }

    private Class<?>[] findParameterTypes(FacesContext context, SimpleMethodExpression methodExpression,
            ExpressionFactory expressionFactory, UIInput[] parameterComponents) {
        Class<?>[] parameterTypes = new Class[methodExpression.getParameters().length];
        for (int i = 0; i < parameterTypes.length; i++) {
            if (parameterComponents[i] != null) {
                Object value = parameterComponents[i].getSubmittedValue();
                if (value != null) {
                    parameterTypes[i] = value.getClass();
                } else {
                    value = parameterComponents[i].getValue();
                    if (value != null) {
                        parameterTypes[i] = value.getClass();
                    }
                }
            }
            if (parameterTypes[i] == null) {
                Object paramterValue = expressionFactory
                        .createValueExpression(methodExpression.getParameters()[i], Object.class)
                        .getValue(context.getELContext());
                parameterTypes[i] = paramterValue != null ? paramterValue.getClass() : null;
            }
        }
        return parameterTypes;
    }

    private UIInput[] findComponents(SimpleMethodExpression methodExpression) {
        String[] parameters = methodExpression.getParameters();
        UIInput[] parameterComponents = new UIInput[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            parameterComponents[i] = findComponent(getParent(), "#{" + parameters[i].trim() + '}');
        }
        return parameterComponents;
    }

    private UIInput findComponent(UIComponent parent, String expression) {
        if (parent instanceof UIInput) {
            UIInput input = (UIInput) parent;
            if (input.getValueExpression("value").getExpressionString().equals(expression)) {
                return input;
            }
        }
        for (UIComponent child : parent.getChildren()) {
            UIInput input = findComponent(child, expression);
            if (input != null) {
                return input;
            }
        }
        return null;
    }

    private Method findMethod(Class<?> type, String name, Class<?>[] parameters) {
        for (Method method : type.getMethods()) {
            if (method.getName().equals(name)) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != parameters.length) {
                    continue;
                }
                boolean match = true;
                for (int i = 0; i < parameters.length; i++) {
                    if (parameters[i] != null && !parameterTypes[i].isAssignableFrom(parameters[i])) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    // TODO currently we simply take the first match... We should resolve based on java resolution rules...
                    return method;
                }
            }
        }
        throw new ELException("method with name '" + name + "' not found in type " + type.getName());
    }
}