/******************************************************************************* * (c) Copyright 2016 Hewlett-Packard Development Company, L.P. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Apache License v2.0 which accompany this distribution. * * The Apache License is available at * http://www.apache.org/licenses/LICENSE-2.0 * *******************************************************************************/ package io.cloudslang.lang.compiler.modeller; import io.cloudslang.lang.compiler.modeller.result.TransformModellingResult; import io.cloudslang.lang.compiler.modeller.transformers.Transformer; import io.cloudslang.lang.entities.SensitivityLevel; import org.apache.commons.lang3.StringUtils; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashMap; import java.util.List; import java.util.Map; public class TransformersHandler { public static final String CLASS = "class "; public static String keyToTransform(Transformer transformer) { String key; if (transformer.keyToTransform() != null) { key = transformer.keyToTransform(); } else { String simpleClassName = transformer.getClass().getSimpleName(); key = StringUtils.substringBefore(simpleClassName, Transformer.class.getSimpleName()); } return key.toLowerCase(); } public Map<String, Serializable> runTransformers(Map<String, Object> rawData, List<Transformer> scopeTransformers, List<RuntimeException> errors) { return runTransformers(rawData, scopeTransformers, errors, "", SensitivityLevel.ENCRYPTED); } public Map<String, Serializable> runTransformers(Map<String, Object> rawData, List<Transformer> scopeTransformers, List<RuntimeException> errors, String errorMessagePrefix, SensitivityLevel sensitivityLevel) { Map<String, Serializable> transformedData = new HashMap<>(); for (Transformer transformer : scopeTransformers) { String key = keyToTransform(transformer); Object value = rawData.get(key); try { @SuppressWarnings("unchecked") TransformModellingResult transformModellingResult = transformer.transform(value, sensitivityLevel); Object data = transformModellingResult.getTransformedData(); if (data != null) { transformedData.put(key, (Serializable) data); } if (rawData.containsKey(key)) { for (RuntimeException rex : transformModellingResult.getErrors()) { errors.add(wrapErrorMessage(rex, errorMessagePrefix)); } } } catch (ClassCastException e) { Class transformerType = getTransformerFromType(transformer); if (value instanceof Map && transformerType.equals(List.class)) { errors.add(new RuntimeException(errorMessagePrefix + "Under property: '" + key + "' there should be a list of values, but instead there is a map.\n" + "By the Yaml spec lists properties are marked with a '- ' (dash followed by a space)")); } else if (value instanceof List && transformerType.equals(Map.class)) { errors.add(new RuntimeException(errorMessagePrefix + "Under property: '" + key + "' there should be a map of values, but instead there is a list.\n" + "By the Yaml spec maps properties are NOT marked with a '- ' (dash followed by a space)")); } else if (value instanceof String && transformerType.equals(Map.class)) { errors.add(new RuntimeException(errorMessagePrefix + "Under property: '" + key + "' there should be a map of values, but instead there is a string.")); } else if (value instanceof String && transformerType.equals(List.class)) { errors.add(new RuntimeException(errorMessagePrefix + "Under property: '" + key + "' there should be a list of values, but instead there is a string.")); } else { String message = "Data for property: " + key + " -> " + rawData.get(key).toString() + " is illegal." + "\n Transformer is: " + transformer.getClass().getSimpleName(); errors.add(new RuntimeException(errorMessagePrefix + message, e)); } } catch (RuntimeException e) { errors.add(wrapErrorMessage(e, errorMessagePrefix)); } } return transformedData; } private Class getTransformerFromType(Transformer transformer) { // Always take the first interface Transformer<F, T> in case of many interfaces // Always take the first parameter F of the Transformer interface Type interfaceType = transformer.getClass().getGenericInterfaces()[0]; Type typeF = ((ParameterizedType) interfaceType).getActualTypeArguments()[0]; if (typeF instanceof ParameterizedType) { return (Class) ((ParameterizedType) typeF).getRawType(); } else if (typeF instanceof Class) { return (Class) typeF; } else { String fullName = typeF.toString(); try { return fullName.startsWith(CLASS) ? Class.forName(fullName.substring(CLASS.length())) : Class.forName(fullName); } catch (ClassNotFoundException e) { return null; } } } private RuntimeException wrapErrorMessage(RuntimeException rex, String errorMessagePrefix) { return new RuntimeException(errorMessagePrefix + rex.getMessage(), rex); } }