com.imsweb.validation.internal.context.JavaContextParser Maven / Gradle / Ivy
/*
* Copyright (C) 2011 Information Management Services, Inc.
*/
package com.imsweb.validation.internal.context;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import org.apache.commons.lang3.math.NumberUtils;
import com.imsweb.validation.ConstructionException;
import com.imsweb.validation.ValidationEngine;
import com.imsweb.validation.internal.context.JavaContextSymbol.JavaContextSymbolType;
/**
* Created on Oct 4, 2011 by murphyr
* @author murphyr
*/
@SuppressWarnings({"java:S1149", "rawtypes"})
public final class JavaContextParser {
/**
* Created on Oct 4, 2011 by murphyr
*/
private JavaContextParser() {
}
/**
* Generates an object (a map, list, integer, or string) based on the expression passed in.
*
* Created on Oct 4, 2011 by murphyr
* @param expression expression to parse
* @param currentContext current context
* @return the parsed expression (a tree)
*/
@SuppressWarnings({"unchecked", "JdkObsolete", "java:S1141"})
public static Object parseContext(String expression, Map currentContext) throws ConstructionException {
Object result;
// this is a bit hackish, but I am parsing out the type hint at the end of the expression instead of using the lexer...
String typeHint = null;
int typeHintIdx = expression.lastIndexOf(" as ");
if (typeHintIdx > 0) {
String content = expression.substring(0, typeHintIdx);
if (content.endsWith("]")) {
typeHint = expression.substring(typeHintIdx + 4);
expression = content;
}
}
JavaContextLexer lexer = new JavaContextLexer(new StringReader(expression));
try {
JavaContextSymbol token = lexer.next_token();
Queue queue = new LinkedList<>();
queue.add(token);
if (token.getType() == JavaContextSymbolType.NUMBER || token.getType() == JavaContextSymbolType.STRING_VAL) {
JavaContextSymbol nextToken = lexer.next_token();
//just a string or a integer
if (nextToken == null)
return token.getValue();
//at this point we only expect a string, an integer, or a range so anything else is invalid syntax
if (nextToken.getType() != JavaContextSymbolType.RANGE)
throw new ConstructionException("Invalid syntax.");
else
//its a range so add it to the queue
queue.add(nextToken);
}
while (token != null) {
token = lexer.next_token();
queue.add(token);
}
result = buildListOrMapFromQueue(queue, currentContext, false);
// a better way to do this is to create the correct instance of the class right away, but this code is a bit complicated...
if (typeHint != null) {
try {
Class> typeClazz = Class.forName(typeHint);
Object obj = typeClazz.getDeclaredConstructor().newInstance();
if (result instanceof List) {
if (!(obj instanceof List) && !(obj instanceof Set))
throw new ConstructionException("Unable to assign list to type " + typeHint);
if (obj instanceof List)
((List)obj).addAll((List)result);
else
((Set)obj).addAll((List)result);
result = obj;
}
else if (result instanceof Map) {
if (!(obj instanceof Map))
throw new ConstructionException("Unable to assign map to type " + typeHint);
((Map)obj).putAll((Map)result);
result = obj;
}
}
catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new ConstructionException(e);
}
}
}
catch (IOException e) {
//should not happen
throw new ConstructionException("Invalid syntax.", e);
}
catch (RuntimeException e2) {
throw new ConstructionException(e2.getMessage(), e2);
}
return result;
}
/**
* Recursive function that takes a queue of tokens, the current context, and a boolean which keeps
* track of whether or not it's currently parsing something that is contained in a list.
*
* Created on Oct 4, 2011 by murphyr
* @param queue queue of tokens
* @param currentContext current context
* @param containsListBeginToken whether the queue contains a list beginning token
* @return a parsed context
*/
@SuppressWarnings({"unchecked", "JdkObsolete", "ConstantConditions"})
private static Object buildListOrMapFromQueue(Queue queue, Map currentContext, boolean containsListBeginToken) throws ConstructionException {
Stack © 2015 - 2025 Weber Informatics LLC | Privacy Policy