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

net.sf.aguacate.config.spi.PathInfoCompilerImpl Maven / Gradle / Ivy

package net.sf.aguacate.config.spi;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import net.sf.aguacate.context.impl.ContextValidatorSql;
import net.sf.aguacate.context.spi.sql.ContextProcessorSql;
import net.sf.aguacate.context.spi.sql.SentenceSql;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlArrayIterator;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlConstant;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlInsert;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlSelectMultipleRow;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlSelectSingle;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlSelectSingleRow;
import net.sf.aguacate.context.spi.sql.impl.SentenceSqlupdate;
import net.sf.aguacate.function.Function;
import net.sf.aguacate.function.Parameter;
import net.sf.aguacate.function.spi.impl.FunctionArrayIterator;
import net.sf.aguacate.function.spi.impl.FunctionConstant;
import net.sf.aguacate.function.spi.impl.FunctionEquals;
import net.sf.aguacate.function.spi.impl.FunctionGreaterThan;
import net.sf.aguacate.function.spi.impl.FunctionGreaterThanToday;
import net.sf.aguacate.function.spi.impl.FunctionLessThan;
import net.sf.aguacate.function.spi.impl.FunctionNotEquals;
import net.sf.aguacate.function.spi.impl.FunctionRename;
import net.sf.aguacate.function.spi.impl.FunctionScript;
import net.sf.aguacate.function.spi.impl.FunctionSelectSingle;
import net.sf.aguacate.function.spi.impl.FunctionZero;
import net.sf.aguacate.model.EntityInfo;
import net.sf.aguacate.model.Field;
import net.sf.aguacate.model.FieldBoolean;
import net.sf.aguacate.model.FieldDynamicDate;
import net.sf.aguacate.model.FieldNumber;
import net.sf.aguacate.model.FieldStaticDateTime;
import net.sf.aguacate.model.FieldString;
import net.sf.aguacate.model.FieldStructureArray;
import net.sf.aguacate.model.FieldType;
import net.sf.aguacate.util.config.datasource.DataSourceCoupling;
import net.sf.aguacate.util.formatter.impl.OutputFormaterImpl;
import net.sf.aguacate.validator.ValidatorConverter;

public class PathInfoCompilerImpl implements PathInfoCompiler {

	private static final Logger LOGGER = LogManager.getLogger(PathInfoCompilerImpl.class);

	private static final String[] METHODS = new String[] { "GET", "POST", "PUT", "DELETE", "GET0", "PATCH" };

	private static final FastDateFormat FMT_TIME;

	private static final FastDateFormat FMT_DATE;

	private static final FastDateFormat FMT_DATETIME;

	static {
		String time = "HH:mm:ss.SSS";
		FMT_TIME = FastDateFormat.getInstance(time);

		String date = "yyyy-MM-dd";
		FMT_DATE = FastDateFormat.getInstance(date);

		String datetime = date + "'T'" + time;
		FMT_DATETIME = FastDateFormat.getInstance(datetime);
	}

	@Override
	public EntityInfo compile(ValidatorConverter validatorConverter, Map data) {
		return processFields(validatorConverter, data, processValidations(data), processSentences(data));
	}

	@SuppressWarnings("unchecked")
	EntityInfo processFields(ValidatorConverter validatorConverter, Map data, List functions,
			List sentences) {
		Map fields = (Map) data.get("fields");
		if (fields == null) {
			return null;
		} else {
			Map> inputFields = new HashMap<>();
			Map> outputFields = new HashMap<>();
			for (Map.Entry entry : fields.entrySet()) {
				String name = entry.getKey();
				Map meta = (Map) entry.getValue();
				parseInputField(name, meta, inputFields);
				parseOutputField(name, meta, outputFields);
			}
			String primary = (String) data.get("primary");
			DataSource dataSource = DataSourceCoupling.getDataSource((String) data.get("datasource"));
			return new EntityInfo(validatorConverter, primary, inputFields, outputFields,
					new ContextValidatorSql(dataSource, functions), new ContextProcessorSql(dataSource, sentences),
					new OutputFormaterImpl());
		}
	}

	@SuppressWarnings("unchecked")
	void parseInputField(String name, Map meta, Map> methods) {
		Map input = (Map) meta.get("input");
		for (String method : METHODS) {
			Map meta2 = (Map) input.get(method);
			if (meta2 != null) {
				Boolean mandatory = (Boolean) meta2.get("mandatory");
				if (mandatory != null) {
					Field field = toField(name, meta, !mandatory.booleanValue());
					if (field != null) {
						Map fields = methods.get(method);
						if (fields == null) {
							methods.put(method, fields = new HashMap<>());
						}
						fields.put(name, field);
					}
				}
			}
		}
	}

	Map toField(Map meta) {
		Map fields = new HashMap<>();
		for (Map.Entry entry : meta.entrySet()) {
			String name = entry.getKey();
			@SuppressWarnings("unchecked")
			Map meta2 = (Map) entry.getValue();
			// TODO: avoid optional with a hardcoded value (false)
			fields.put(name, toField(name, meta2, false));
		}
		return fields;
	}

	Field toField(String name, Map meta, boolean optional) {
		String string = (String) meta.get("type");
		FieldType type = FieldType.valueOf(string);
		switch (type) {
		case TIME: {
			Date minValue = parse(FMT_TIME, (String) meta.get("minval"));
			Date maxValue = parse(FMT_TIME, (String) meta.get("maxval"));
			return new FieldStaticDateTime(name, type, optional, minValue, maxValue);
		}
		case DYNAMIC_DATE:
			return new FieldDynamicDate(name, type, optional, (String) meta.get("minval"), (String) meta.get("maxval"));
		case DATE: {
			Date minValue = parse(FMT_DATE, (String) meta.get("minval"));
			Date maxValue = parse(FMT_DATE, (String) meta.get("maxval"));
			return new FieldStaticDateTime(name, type, optional, minValue, maxValue);
		}
		case DATETIME: {
			Date minValue = parse(FMT_DATETIME, (String) meta.get("minval"));
			Date maxValue = parse(FMT_DATETIME, (String) meta.get("maxval"));
			return new FieldStaticDateTime(name, type, optional, minValue, maxValue);
		}
		case FLOAT: {
			BigDecimal minValue = new BigDecimal((String) meta.get("minval"));
			BigDecimal maxValue = new BigDecimal((String) meta.get("maxval"));
			return new FieldNumber(name, type, optional, minValue, maxValue);
		}
		case INTEGER: {
			BigInteger minValue = new BigInteger((String) meta.get("minval"));
			BigInteger maxValue = new BigInteger((String) meta.get("maxval"));
			return new FieldNumber(name, type, optional, minValue, maxValue);
		}
		case STRING: {
			int minLenth = Integer.parseInt((String) meta.get("minlen"));
			int maxLength = Integer.parseInt((String) meta.get("maxlen"));
			String regex = (String) meta.get("regex");
			LOGGER.trace("{} regex to compile: {}", name, regex);
			Pattern pattern = Pattern.compile(regex);
			return new FieldString(name, type, optional, minLenth, maxLength, pattern);
		}
		case BOOLEAN: {
			return new FieldBoolean(name, type, optional);
		}
		case STRUCTURE_ARRAY: {
			@SuppressWarnings("unchecked")
			Map sub = (Map) meta.get("data");
			return new FieldStructureArray(name, type, optional, toField(sub));
		}
		default:
			throw new IllegalArgumentException(string);
		}
	}

	Date parse(FastDateFormat parser, String value) {
		try {
			return parser.parse(value);
		} catch (ParseException e) {
			throw new IllegalArgumentException(value);
		}
	}

	@SuppressWarnings("unchecked")
	List processValidations(Map data) {
		List> validations = (List>) data.get("validations");
		if (validations == null) {
			return Collections.emptyList();
		} else {
			List functions = new ArrayList<>();
			for (Map validation : validations) {
				String name = (String) validation.get("name");
				String type = (String) validation.get("type");
				String outputName = (String) validation.get("outputName");
				List parameters = (List) validation.get("parameters");
				List methods = (List) validation.get("methods");
				List params;
				if (parameters == null || parameters.isEmpty()) {
					params = Collections.emptyList();
				} else {
					params = new ArrayList<>();
					for (String parameter : parameters) {
						params.add(new Parameter(parameter));
					}
				}
				functions.add(toFunction(validation, methods, name, type, params, outputName));
			}
			return functions;
		}
	}

	Function toFunction(Map validation, Collection methods, String name, String type,
			List parameters, String outputName) {
		Function function;
		switch (type) {
		case "LT":
			if (parameters.size() == 2) {
				function = new FunctionLessThan<>(methods, name, parameters.get(0), parameters.get(1));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 2");
			}
			break;
		case "GT":
			if (parameters.size() == 2) {
				function = new FunctionGreaterThan<>(methods, name, parameters.get(0), parameters.get(1));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 2");
			}
			break;
		case "GT_TODAY":
			if (parameters.size() == 1) {
				function = new FunctionGreaterThanToday(methods, name, parameters.get(0));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 1");
			}
			break;
		case "EQ":
			if (parameters.size() == 2) {
				function = new FunctionEquals(methods, name, parameters.get(0), parameters.get(1));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 2");
			}
			break;
		case "NE":
			if (parameters.size() == 2) {
				function = new FunctionNotEquals(methods, name, parameters.get(0), parameters.get(1));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 2");
			}
			break;
		case "ZERO":
			if (parameters.size() == 1) {
				function = new FunctionZero(methods, name, parameters.get(0));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 1");
			}
			break;
		case "NOT_ZERO":
			if (parameters.size() == 1) {
				function = new FunctionZero(methods, name, parameters.get(0));
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 1");
			}
			break;
		case "REN":
			if (parameters.size() == 1) {
				function = new FunctionRename(methods, name, parameters.get(0), outputName);
			} else {
				throw new IllegalArgumentException(
						"The number or parameters for function type '" + type + "'(" + name + ") must be 1");
			}
			break;
		case "SCRIPT":
			function = new FunctionScript(methods, name, parameters, outputName,
					(String) validation.get("scriptName"), (String) validation.get("functionName"));
			break;
		case "ARRAY_ITERATOR": {
			List subvalidations = processValidations(validation);
			List newmethods = new ArrayList<>();
			for (Function current : subvalidations) {
				for (String method : METHODS) {
					if (current.validFor(method) && !newmethods.contains(method)) {
						newmethods.add(method);
					}
				}
			}
			function = new FunctionArrayIterator(newmethods, name, parameters, outputName, subvalidations);
			break;
		}
		case "CONSTANT":
			function = new FunctionConstant(methods, name, parameters, outputName, validation.get("value"));
			break;
		case "SELECT_SINGLE":
			function = new FunctionSelectSingle(methods, name, parameters, outputName, (String) validation.get("table"));
			break;
		default:
			throw new IllegalArgumentException(type);
		}
		return function;
	}

	@SuppressWarnings("unchecked")
	List processSentences(Map data) {
		List> sentences = (List>) data.get("sentences");
		if (sentences == null) {
			return Collections.emptyList();
		} else {
			List result = new ArrayList<>();
			for (Map sentence : sentences) {
				result.add(toSentence(sentence));
			}
			return result;
		}
	}

	SentenceSql toSentence(Map data) {
		String type = (String) data.get("type");
		String name = (String) data.get("name");
		String table = (String) data.get("table");
		@SuppressWarnings("unchecked")
		List required = (List) data.get("required");
		@SuppressWarnings("unchecked")
		List optional = (List) data.get("optional");
		@SuppressWarnings("unchecked")
		List methods = (List) data.get("methods");
		SentenceSql sentence;
		switch (type) {
		case "INSERT":
			sentence = new SentenceSqlInsert(name, table, methods, required, optional, (String) data.get("outputName"));
			break;
		case "UPDATE":
			sentence = new SentenceSqlupdate(name, table, methods, required, optional);
			break;
		case "SELECT_SINGLE_ROW":
			sentence = new SentenceSqlSelectSingleRow(name, table, methods, required, optional,
					(String) data.get("outputName"));
			break;
		case "SELECT_SINGLE":
			sentence = new SentenceSqlSelectSingle(name, table, methods, required, optional,
					(String) data.get("outputName"));
			break;
		case "SELECT_MULTIPLE_ROW":
			sentence = new SentenceSqlSelectMultipleRow(name, table, methods, required, optional,
					(String) data.get("outputName"));
			break;
		case "ARRAY_ITERATOR": {
			List subsentences = processSentences(data);
			List newmethods = new ArrayList<>();
			for (SentenceSql current : subsentences) {
				for (String method : METHODS) {
					if (current.validFor(method) && !newmethods.contains(method)) {
						newmethods.add(method);
					}
				}
			}
			sentence = new SentenceSqlArrayIterator(name, newmethods, required, optional, subsentences);
			break;
		}
		case "CONSTANT":
			sentence = new SentenceSqlConstant(name, methods, (String) data.get("outputName"), data.get("value"));
			break;
		default:
			throw new IllegalArgumentException(type);
		}
		return sentence;
	}

	@SuppressWarnings("unchecked")
	void parseOutputField(String name, Map meta, Map> outputFields) {
		String string = (String) meta.get("type");
		FieldType type = FieldType.valueOf(string);
		List output = (List) meta.get("output");
		for (String method : output) {
			Map fields = outputFields.get(method);
			if (fields == null) {
				fields = new HashMap<>();
				outputFields.put(method, fields);
			}
			fields.put(name, type);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy