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

de.alpharogroup.wicket.component.search.ComponentExpression Maven / Gradle / Ivy

/*
 *    Copyright 2009 Richard Wilkinson

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package de.alpharogroup.wicket.component.search;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;

/**
 * This class provides several methods for the search of wicket {@link org.apache.wicket.Component}
 * s.
 */
public class ComponentExpression
{

	private static final String ANY_COMPONENT_MATCHER = "*";
	private static final String ANY_COMPONENT_RECURSIVE_MATCHER = "**";

	/**
	 * Search for the first {@link org.apache.wicket.Component} with the given expression in the
	 * given parent. Internally this method calls the
	 * {@link ComponentExpression#findAllComponents(org.apache.wicket.Component, String)} that
	 * returns a list and if this list is not empty the first element will be returned.
	 * 
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expression
	 *            the expression for search.
	 * @return the first {@link org.apache.wicket.Component} with the given expression in the given
	 *         parent or null if nothing is found.
	 */
	public static Component findComponent(Component parent, String expression)
	{
		List results = findAllComponents(parent, expression);
		if (results.isEmpty())
		{
			return null;
		}
		else
		{
			return results.get(0);
		}
	}

	/**
	 * Search for the first {@link org.apache.wicket.Component} with the given expression in the
	 * given parent with the given class type restriction. Internally this method calls the
	 * {@link ComponentExpression#findAllComponents(org.apache.wicket.Component, String, Class)}
	 * that returns a list and if this list is not empty the first element will be returned.
	 * 
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expression
	 *            the expression for search.
	 * @param typeRestriction
	 *            the class type restriction for the search.
	 * @return the first {@link org.apache.wicket.Component} with the given expression in the given
	 *         parent or null if nothing is found.
	 */
	public static Component findComponent(Component parent, String expression,
		Class typeRestriction)
	{
		List results = findAllComponents(parent, expression, typeRestriction);
		if (results.isEmpty())
		{
			return null;
		}
		else
		{
			return results.get(0);
		}
	}

	/**
	 * Search for all {@link org.apache.wicket.Component}s with the given expression in the given
	 * parent with a {@link org.apache.wicket.Component} class type restriction.
	 *
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expression
	 *            the expression for search.
	 * @return all found {@link org.apache.wicket.Component}s in a {@link java.util.List} with the
	 *         given expression in the given parent with the given class type restriction or an
	 *         empty {@link java.util.List} if nothing is found.
	 */
	public static List findAllComponents(Component parent, String expression)
	{
		return findAllComponents(parent, expression, Component.class);

	}

	/**
	 * Search for all {@link org.apache.wicket.Component}s with the given expression in the given
	 * parent with the given class type restriction.
	 *
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expression
	 *            the expression for search.
	 * @param typeRestriction
	 *            the class type restriction for the search.
	 * @return all found {@link org.apache.wicket.Component}s in a {@link java.util.List} with the
	 *         given expression in the given parent with the given class type restriction or an
	 *         empty {@link java.util.List} if nothing is found.
	 */
	public static List findAllComponents(Component parent, String expression,
		Class typeRestriction)
	{
		if (expression == null || expression.equals(""))
		{
			return Collections.emptyList();
		}
		return findComponent(
			parent,
			new LinkedList(Arrays.asList(expression.split(Character
				.toString(Component.PATH_SEPARATOR)))), typeRestriction);
	}

	/**
	 * Search for all {@link org.apache.wicket.Component}s with the given list of expressions in the
	 * given parent with the given class type restriction.
	 *
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expressionListIn
	 *            the list with the expressions for the search.
	 * @param typeRestriction
	 *            the class type restriction for the search.
	 * @return all found {@link org.apache.wicket.Component}s in a {@link java.util.List} with the
	 *         given expression in the given parent with the given class type restriction or an
	 *         empty {@link java.util.List} if nothing is found.
	 */
	private static List findComponent(Component parent,
		LinkedList expressionListIn, Class typeRestriction)
	{

		LinkedList expressionList = new LinkedList(expressionListIn);

		if (expressionList.isEmpty())
		{
			if (typeRestriction.isAssignableFrom(parent.getClass()))
			{
				return Arrays.asList(parent);
			}
			else
			{
				return Collections.emptyList();
			}
		}
		else
		{
			String rawFirst = expressionList.getFirst();
			Collection conditions = parseConditions(rawFirst);
			final String first = rawFirst.replaceAll("\\s*\\[.*\\]\\s*", "");

			if (!first.equals(ANY_COMPONENT_RECURSIVE_MATCHER))
			{
				expressionList.removeFirst();
				List allMatches = getChild(parent, first, conditions);
				if (allMatches.isEmpty())
				{
					return Collections.emptyList();
				}
				else
				{
					List finallyMatchedComponents = new ArrayList();
					for (Component aMatch : allMatches)
					{
						finallyMatchedComponents.addAll(findComponent(aMatch, expressionList,
							typeRestriction));
					}
					return finallyMatchedComponents;
				}
			}
			else if (expressionList.size() == 1)
			{
				List allMatches = new ArrayList();
				if (parent instanceof MarkupContainer)
				{
					for (Component aMatch : getAllChildren((MarkupContainer)parent))
					{
						if (typeRestriction.isAssignableFrom(aMatch.getClass())
							&& evaluateConditions(conditions, aMatch))
						{
							allMatches.add(aMatch);
						}
						allMatches.addAll(findComponent(aMatch, expressionList, typeRestriction));
					}
					return allMatches;
				}
				else
				{
					return Collections.emptyList();
				}
			}
			else
			{
				List allMatches = new ArrayList();
				LinkedList fake = new LinkedList();
				fake.add(ANY_COMPONENT_RECURSIVE_MATCHER);
				List allPotentialParents = findComponent(parent, fake, Component.class);
				expressionList.removeFirst();
				for (Component aParent : allPotentialParents)
				{
					if (evaluateConditions(conditions, aParent))
					{
						allMatches.addAll(findComponent(aParent, expressionList, typeRestriction));
					}
				}
				return allMatches;
			}
		}
	}

	/**
	 * Search for all child {@link org.apache.wicket.Component}s with the given expression and the
	 * given parent with the given collection of {@link Condition}s as filter.
	 * 
	 * @param parent
	 *            the parent that will be the start point to search.
	 * @param expression
	 *            the expression for search.
	 * @param conditions
	 *            a collection of {@link Condition}s to filter.
	 * @return all found child {@link org.apache.wicket.Component}s in a {@link java.util.List}.
	 */
	private static List getChild(Component parent, String expression,
		Collection conditions)
	{

		if (parent instanceof MarkupContainer)
		{
			MarkupContainer parentContainer = (MarkupContainer)parent;
			if (expression.equals(ANY_COMPONENT_MATCHER))
			{
				List allChildren = getAllChildren(parentContainer);
				List allChildrenMatchingCondition = new ArrayList();
				for (Component child : allChildren)
				{
					if (child != null && evaluateConditions(conditions, child))
					{
						allChildrenMatchingCondition.add(child);
					}
				}
				return allChildrenMatchingCondition;
			}
			else
			{

				Component comp = parentContainer.get(expression);

				if (comp == null || !evaluateConditions(conditions, comp))
				{
					return Collections.emptyList();
				}
				else
				{
					return Arrays.asList(comp);
				}
			}
		}
		else
		{
			return Collections.emptyList();
		}
	}

	/**
	 * Evaluates the given {@link org.apache.wicket.Component} with the given collection of
	 * {@link Condition}s.
	 * 
	 * @param conditions
	 *            a collection of {@link Condition}s to evaluate.
	 * @param component
	 *            the {@link org.apache.wicket.Component} that the evaluation will be executed.
	 * @return true if the evaluation is successful otherwise false.
	 */
	private static final boolean evaluateConditions(Collection conditions,
		Component component)
	{
		boolean result = true;
		for (Condition condition : conditions)
		{
			switch (condition.getAttr())
			{
				case ENABLED : {
					result = result
						&& (component.isEnabledInHierarchy() == condition.getCondition());
					break;
				}
				case VISIBLE : {
					result = result
						&& (component.isVisibleInHierarchy() == condition.getCondition());
				}
			}
			if (!result)
			{
				break;
			}
		}
		return result;
	}

	/**
	 * Parses the given expression to a collection of {@link Condition}s.
	 * 
	 * @param expression
	 *            the expression to parse.
	 * @return a collection of {@link Condition}s.
	 */
	private static final Collection parseConditions(String expression)
	{
		List parsedConditions = new ArrayList();
		Pattern pattern = Pattern.compile(".*\\[\\s*(.*?)\\s*\\]\\w*", Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(expression);
		if (matcher.matches())
		{
			String conditionString = matcher.group(1);
			String[] conditions = conditionString.split("\\s*(and|&)\\s*");
			for (String aCondition : conditions)
			{
				Condition.Attr attr = null;
				Boolean condition = null;
				String[] parts = null;
				if (aCondition.contains("="))
				{
					parts = aCondition.split("\\s*=\\s*");
					if (parts.length == 2)
					{
						if (parts[0].toUpperCase().equals(Condition.Attr.VISIBLE.toString()))
						{
							attr = Condition.Attr.VISIBLE;
						}
						else if (parts[0].toUpperCase().equals(Condition.Attr.ENABLED.toString()))
						{
							attr = Condition.Attr.ENABLED;
						}
						if (parts[1].toUpperCase().equals(Boolean.TRUE.toString().toUpperCase()))
						{
							condition = Boolean.TRUE;
						}
						else if (parts[1].toUpperCase().equals(
							Boolean.FALSE.toString().toUpperCase()))
						{
							condition = Boolean.FALSE;
						}
						if (attr != null && condition != null)
						{
							parsedConditions.add(new Condition(attr, condition));
						}
					}
				}

			}
		}
		return parsedConditions;
	}

	/**
	 * Simple pojo class that holds an attribute(visible or enabled) and a condition.
	 */
	private static final class Condition
	{
		/**
		 * Simple enum that holds two states of an attribute.
		 */
		private enum Attr
		{
			/**
			 * The visible state.
			 */
			VISIBLE,
			/**
			 * The enabled state.
			 */
			ENABLED;
		}

		/**
		 * The state of the condition.
		 */
		private final Attr attr;
		/**
		 * The flag condition.
		 */
		private final boolean condition;

		/**
		 * Default constructor.
		 * 
		 * @param attr
		 *            The state of the condition.
		 * @param condition
		 *            The flag condition.
		 */
		public Condition(Attr attr, boolean condition)
		{
			this.attr = attr;
			this.condition = condition;
		}

		/**
		 * Gets the state of the condition.
		 * 
		 * @return the state of the condition.
		 */
		public Attr getAttr()
		{
			return attr;
		}

		/**
		 * Gets the flag condition.
		 * 
		 * @return the flag condition.
		 */
		public boolean getCondition()
		{
			return condition;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String toString()
		{
			return String.format("Condition [attr=%s, condition=%s]", attr, condition);
		}
	}

	/**
	 * Search for all child {@link org.apache.wicket.Component}s from the given parent.
	 * 
	 * @param parent
	 *            The parent
	 * @return all child {@link org.apache.wicket.Component}s from the given parent.
	 */
	private static List getAllChildren(MarkupContainer parent)
	{
		List children = new ArrayList();
		Iterator iter = parent.iterator();
		while (iter.hasNext())
		{
			children.add(iter.next());
		}
		return children;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy