package org.jboss.windup.rules.apps.java.xml;
import static org.joox.JOOX.$;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.jboss.windup.ast.java.data.TypeReferenceLocation;
import org.jboss.windup.config.exception.ConfigurationException;
import org.jboss.windup.config.parser.ElementHandler;
import org.jboss.windup.config.parser.NamespaceElementHandler;
import org.jboss.windup.config.parser.ParserContext;
import org.jboss.windup.config.parser.xml.RuleProviderHandler;
import org.jboss.windup.rules.apps.java.condition.JavaClass;
import org.jboss.windup.rules.apps.java.condition.JavaClassBuilder;
import org.jboss.windup.rules.apps.java.condition.JavaClassBuilderAt;
import org.jboss.windup.rules.apps.java.condition.annotation.AnnotationCondition;
import org.jboss.windup.rules.apps.java.condition.annotation.AnnotationTypeCondition;
import org.jboss.windup.util.exception.WindupException;
import org.ocpsoft.rewrite.config.Condition;
import org.w3c.dom.Element;
/**
*
* Represents a {@link JavaClass} {@link Condition}.
*
* Example:
*
* <pre>
* <javaclass type="javax.servlet.http.HttpServletRequest">
* <location>METHOD_PARAMETER</location>
* <annotation-list-contion|annotation-literal|annotation-type />
* </javaclass>
* </pre>
*
* @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
*
*/
@NamespaceElementHandler(elementName = JavaClassHandler.ELEM_NAME, namespace = RuleProviderHandler.WINDUP_RULE_NAMESPACE)
public class JavaClassHandler implements ElementHandler<JavaClassBuilderAt>
{
public static final String ELEM_NAME = "javaclass";
private static final String ATTR_REFERENCES = "references";
@Override
public JavaClassBuilderAt processElement(ParserContext handlerManager, Element element)
throws ConfigurationException
{
String type = $(element).attr(ATTR_REFERENCES);
String as = $(element).attr("as");
String from = $(element).attr("from");
String matchesSource = $(element).attr("matchesSource");
if (StringUtils.isBlank(type))
{
throw new WindupException("The '" + ELEM_NAME + "' element must have a non-empty '" + ATTR_REFERENCES + "' attribute");
}
List<TypeReferenceLocation> locations = new ArrayList<>();
List<Element> children = $(element).children().get();
Map<String, AnnotationCondition> conditionMap = new HashMap<>();
List<AnnotationTypeCondition> additionalAnnotationConditions = new ArrayList<>();
for (Element child : children)
{
switch (child.getNodeName())
{
case "location":
TypeReferenceLocation location = handlerManager.processElement(child);
locations.add(location);
break;
case AnnotationTypeConditionHandler.ANNOTATION_TYPE:
case AnnotationListConditionHandler.ANNOTATION_LIST_CONDITION:
case AnnotationLiteralConditionHandler.ANNOTATION_LITERAL:
String name = child.getAttribute(AnnotationConditionHandler.NAME);
AnnotationCondition annotationCondition = handlerManager.processElement(child);
if (StringUtils.isBlank(name))
{
if (!(annotationCondition instanceof AnnotationTypeCondition))
throw new WindupException("Additional Annotation Condition must be an " +
AnnotationTypeConditionHandler.ANNOTATION_TYPE + " condition. Could it be that the '" +
AnnotationConditionHandler.NAME + "' property is missing?");
additionalAnnotationConditions.add((AnnotationTypeCondition)annotationCondition);
}
else
{
if (conditionMap.containsKey(name))
throw new WindupException("Duplicate condition detected on annotation element: " + name);
conditionMap.put(name, annotationCondition);
}
break;
}
}
JavaClassBuilder javaClassReferences;
if (from != null)
{
javaClassReferences = JavaClass.from(from).references(type);
}
else
{
javaClassReferences = JavaClass.references(type);
}
if (matchesSource != null)
{
javaClassReferences.matchesSource(matchesSource);
}
String namePattern = $(element).attr("in");
if (!StringUtils.isBlank(namePattern))
{
javaClassReferences.inType(namePattern);
}
JavaClassBuilderAt javaClass = javaClassReferences.at(
locations.toArray(new TypeReferenceLocation[locations.size()]));
for (Map.Entry<String, AnnotationCondition> entry : conditionMap.entrySet())
{
javaClass.annotationMatches(entry.getKey(), entry.getValue());
}
for (AnnotationTypeCondition condition : additionalAnnotationConditions)
{
javaClass.annotationMatches(condition);
}
if (as != null)
{
javaClass.as(as);
}
return javaClass;
}
}