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

net.jakubholy.jeeutils.jsfelcheck.validator.jsf12.MethodFakingFunctionMapper Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 net.jakubholy.jeeutils.jsfelcheck.validator.jsf12;

import org.apache.el.parser.AstFunction;
import org.apache.el.parser.ELParser;
import org.apache.el.parser.Node;
import org.apache.el.parser.NodeVisitor;

import javax.el.FunctionMapper;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * Instead of resolving to the correct Method based on prefix, name, taglib URI and
 * information in a taglib info file, this mapper just returns a suitable
 * generic method taking the expected number of parameters.
 * 

* In the future I may implement/reuse a true function mapper. */ public class MethodFakingFunctionMapper extends FunctionMapper { /** * For each function node found in an EL, remember the number if its * children (arity). */ private final class FunctionArityExtractingVisitor implements NodeVisitor { private final Map functionArity = new HashMap(); @Override public void visit(Node n) throws Exception { if (n instanceof AstFunction) { visitFunction((AstFunction) n); } } private void visitFunction(AstFunction function) throws Exception { String nodeFunctionQName = function.getPrefix() + ":" + function.getLocalName(); functionArity.put(nodeFunctionQName, function.jjtGetNumChildren()); } public Map getFunctionArities() { return functionArity; } } private static final String DEFAULT_RESULT = ""; // CHECKSTYLE:OFF static final Method[] FAKE_METHODS = new Method[] { createFakeMethod(0) , createFakeMethod(1) , createFakeMethod(2) , createFakeMethod(3) , createFakeMethod(4) , createFakeMethod(5) }; // CHECKSTYLE:ON private final Map functionToAritiesCache = new HashMap(); private final Set currentExpressionsFunctions = new TreeSet(); private String currentExpression; private static Method createFakeMethod(int arity) { Class[] argumentTypes = new Class[arity]; Arrays.fill(argumentTypes, Object.class); try { return MethodFakingFunctionMapper.class.getDeclaredMethod( "fakeMethod" + arity , argumentTypes); } catch (SecurityException e) { throw new IllegalStateException(e); } catch (NoSuchMethodException e) { throw new IllegalStateException(e); } } // CHECKSTYLE:OFF public static String fakeMethod0() { return DEFAULT_RESULT; } public static String fakeMethod1(Object p1) { return DEFAULT_RESULT; } public static String fakeMethod2(Object p1, Object p2) { return DEFAULT_RESULT; } public static String fakeMethod3(Object p1, Object p2, Object p3) { return DEFAULT_RESULT; } public static String fakeMethod4(Object p1, Object p2, Object p3, Object p4) { return DEFAULT_RESULT; } public static String fakeMethod5(Object p1, Object p2, Object p3, Object p4, Object p5) { return DEFAULT_RESULT; } // hopefully nobody uses method of more than 5 parameters // CHECKSTYLE:ON public Collection getLastExpressionsFunctionQNames() { return currentExpressionsFunctions; } @Override public Method resolveFunction(String prefix, String name) { final String resolvedFunctionQName = prefix + ":" + name; // FIXME The code below allows for a function name to have just one number of parameters, i.e. no f(1), f(1,2) // What does the specification say? Integer arity = functionToAritiesCache.get(resolvedFunctionQName); if (arity == null) { Map functionsAndAritiesInCurrentEL = extractFunctionArities(); arity = functionsAndAritiesInCurrentEL.get(resolvedFunctionQName); functionToAritiesCache.putAll(functionsAndAritiesInCurrentEL); } if (arity == null) { throw new IllegalStateException("Couldn't determine the arity of the function " + resolvedFunctionQName + " from the EL '" + getCurrentExpressionOrFail() + "' - not found in it."); } else if (arity >= FAKE_METHODS.length) { throw new IllegalArgumentException("Currently we only can fake methods with up to 5 parameters but " + resolvedFunctionQName + " has " + arity + ". This is really a bad practice anyway."); } else { currentExpressionsFunctions.add(resolvedFunctionQName); return FAKE_METHODS[arity]; } } /** * Extract all arities of all functions in the current EL expression. */ private Map extractFunctionArities() { Node parsedEl = ELParser.parse(getCurrentExpressionOrFail()); try { FunctionArityExtractingVisitor arityExtractingVisitor = new FunctionArityExtractingVisitor(); parsedEl.accept(arityExtractingVisitor); return arityExtractingVisitor.getFunctionArities(); } catch (Exception e) { throw new IllegalStateException("Unexpected failure parsing the EL " + getCurrentExpressionOrFail(), e); } } public void setCurrentExpression(String currentExpression) { this.currentExpression = currentExpression; currentExpressionsFunctions.clear(); } private String getCurrentExpressionOrFail() { if (currentExpression == null) { throw new IllegalStateException("Current EL expression not set!"); } return currentExpression; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy