/* * ****************************************************************************** * MontiCore Language Workbench * Copyright (c) 2016, MontiCore, All rights reserved. * * This project is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this project. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************** */ package de.monticore.generating.templateengine; import static com.google.common.base.Preconditions.checkArgument; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import de.se_rwth.commons.logging.Log; /** * This class adds the signature methods tc.params(...) and tc.result(...) to * the existing TemplateController. * * @author Jerome Pfeiffer */ public class ExtendedTemplateController extends TemplateController { /** * Ensures tc.params(...) is only called once */ private boolean parametrized = false; /** * Ensures tc.result(...) is only called once */ private boolean resultized = false; /** * Constructor for de.montiarc.generator.codegen.MyTemplateController * * @param tcConfig * @param templatename */ public ExtendedTemplateController(TemplateControllerConfiguration tcConfig, String templatename) { super(tcConfig, templatename); } /** * Compares types of the passed params with the arguments passed in the * template call. Additionally signatures the names of the parameters. Method * is important for inter Template calls and for users who do not use the * generated template class with its static generate method. All types that * are no java library types have to be defined fully qualified. * * @param params */ public void params(String... params) { checkArgument(!parametrized, "0xA5299 Template '" + getTemplatename() + "': tried to invoke params() twice"); List<Object> arguments = getArguments(); List<String> names = getSignature(); // throws error when argument size != param size checkArgument(params.length == arguments.size(), "0xA5296 Template '" + getTemplatename() + "': Parameter size (#" + params.length + ") and number of arguments (#" + arguments.size() + ") mismatch."); List<String> toSignature = new ArrayList<String>(); // compares params and args for (int i = 0; i < arguments.size(); i++) { Object argument = arguments.get(i); String parameter = params[i]; String paramType = parameter.substring(0, parameter.indexOf(" ")); paramType = paramType.trim(); if (paramType.contains("<")) { paramType = paramType.substring(0, paramType.indexOf("<")); } String paramName = parameter.substring(parameter.indexOf(" ") + 1); Class argumentClass = argument.getClass(); String argumentClassName = argumentClass.getName(); // checks whether argument type and param type are equal try with java // library types otherwise if (!paramType.equals(argumentClassName)) { Optional<Class> javaLibraryType = getJavaLibraryType(paramType); boolean isAssignable = false; if (javaLibraryType.isPresent()) { isAssignable = javaLibraryType.get().isAssignableFrom(argumentClass); // if it is not assignable with java library type it might be a number if (!isAssignable) { isAssignable = Number.class.isAssignableFrom(javaLibraryType.get()) && Number.class.isAssignableFrom(argumentClass); } } checkArgument(isAssignable, "0xA5301 Template '" + getTemplatename() + "': passed argument type (" + argumentClassName + ") and type of signature parameter (" + paramType + " " + paramName + ") mismatch."); } // Case 1: No Signature -> we have to signature the paramnames if (names.isEmpty()) { toSignature.add(paramName); } // Case 2: User wrote signature() additionally to params() -> we do not // need to signature the parameter names, but compare them to the // parameter names in the params() method. else { String argumentName = names.get(i); checkArgument(argumentName.equals(paramName), "0xA5300 Template '" + getTemplatename() + "': Parameter name (" + paramName + ") and name of parameter in signature (" + argumentName + ") mismatch."); } } if (!toSignature.isEmpty()) { signature(toSignature); } parametrized = true; } /** * Loads java library types to the passed {@link paramType} * * @param argumentClass * @return */ private Optional<Class> getJavaLibraryType(String paramType) { // maps primitive data types to wrapper classes Map<String, String> primitiveTypes = new HashMap<String, String>(); primitiveTypes.put("long", "java.lang.Long"); primitiveTypes.put("int", "java.lang.Integer"); primitiveTypes.put("short", "java.lang.Short"); primitiveTypes.put("double", "java.lang.Double"); primitiveTypes.put("float", "java.lang.Float"); primitiveTypes.put("byte", "java.lang.Byte"); primitiveTypes.put("char", "java.lang.Character"); primitiveTypes.put("boolean", "java.lang.Boolean"); // 1. tries to load the passed type try { Class c = Class.forName(paramType); return Optional.of(c); } catch (ClassNotFoundException e) { // Log.info("Class " + paramType + " not found!", "ExtendedTemplateController"); } // 2. this packages are searched to find the fqn of the passed paramType String[] packagesToSearch = { "java.lang", "java.util" }; Optional<Class> fqnLibraryType = Optional.empty(); for (String _package : packagesToSearch) { try { Class c = Class.forName(_package + "." + paramType); return Optional.of(c); } catch (ClassNotFoundException e) { // Log.info("Class " + _package + "." + paramType + " not found!", "ExtendedTemplateController"); } } // 3. try primitive types if (primitiveTypes.containsKey(paramType)) { Class c; try { c = Class.forName(primitiveTypes.get(paramType)); return Optional.of(c); } catch (ClassNotFoundException e) { // Log.info("Class " + primitiveTypes.get(paramType) + " not found!", "ExtendedTemplateController"); } } return fqnLibraryType; } /** * Checks whether there are more than one result definitions. * * @param result */ public void result(String result) { checkArgument(!resultized, "0xA5302 Template '" + getTemplatename() + "': tried to invoke result() twice"); resultized = true; } }