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

org.eclipse.equinox.p2.query.QueryUtil Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2010, 2013 Cloudsmith Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Cloudsmith Inc. - initial API and implementation
 *     IBM Corporation - ongoing development
 *******************************************************************************/
package org.eclipse.equinox.p2.query;

import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
import org.eclipse.equinox.internal.p2.metadata.expression.*;
import org.eclipse.equinox.internal.p2.metadata.expression.Expression.VariableFinder;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.expression.*;

/**
 * Helper class for query related tasks.
 * @since 2.0
 */
public class QueryUtil {

	public static final IQuery ALL_UNITS = QueryUtil.createMatchQuery(ExpressionUtil.TRUE_EXPRESSION);

	public static final String ANY = "*"; //$NON-NLS-1$

	public static final IQuery NO_UNITS = QueryUtil.createQuery("limit(0)"); //$NON-NLS-1$

	public static final String PROP_TYPE_CATEGORY = "org.eclipse.equinox.p2.type.category"; //$NON-NLS-1$

	public static final String PROP_TYPE_GROUP = "org.eclipse.equinox.p2.type.group"; //$NON-NLS-1$

	public static final String PROP_TYPE_PATCH = "org.eclipse.equinox.p2.type.patch"; //$NON-NLS-1$

	private static final IExpression matchesRequirementsExpression = ExpressionUtil.parse("$0.exists(r | this ~= r)"); //$NON-NLS-1$

	private static final IExpression matchIU_ID = ExpressionUtil.parse("id == $0"); //$NON-NLS-1$
	private static final IExpression matchIU_IDAndRange = ExpressionUtil.parse("id == $0 && version ~= $1"); //$NON-NLS-1$
	private static final IExpression matchIU_IDAndVersion = ExpressionUtil.parse("id == $0 && version == $1"); //$NON-NLS-1$
	private static final IExpression matchIU_Range = ExpressionUtil.parse("version ~= $0"); //$NON-NLS-1$
	private static final IExpression matchIU_Version = ExpressionUtil.parse("version == $0"); //$NON-NLS-1$
	private static final IExpression matchIU_propAny = ExpressionUtil.parse("properties[$0] != null"); //$NON-NLS-1$
	private static final IExpression matchIU_propNull = ExpressionUtil.parse("properties[$0] == null"); //$NON-NLS-1$
	private static final IExpression matchIU_propTrue = ExpressionUtil.parse("properties[$0] == true"); //$NON-NLS-1$
	private static final IExpression matchIU_propValue = ExpressionUtil.parse("properties[$0] == $1"); //$NON-NLS-1$

	/**
	 * Creates a queryable that combines the given collection of input queryables
	 * 
	 * @param queryables The collection of queryables to be combined
	 */
	public static  IQueryable compoundQueryable(Collection> queryables) {
		// don't suppress the warning as it will cause warnings in the official build
		// see bug 423628. Write this without unchecked conversion.
		return new CompoundQueryable(queryables.toArray(new IQueryable[queryables.size()]));
	}

	/**
	 * Creates a queryable that combines the two provided input queryables
	 * 
	 * @param query1 The first queryable
	 * @param query2 The second queryable
	 */
	@SuppressWarnings("unchecked")
	public static  IQueryable compoundQueryable(IQueryable query1, IQueryable query2) {
		return new CompoundQueryable(new IQueryable[] {query1, query2});
	}

	/**
	 * Creates a compound query that combines the given queries. If all queries
	 * are candidate match queries, then the queries will be concatenated as a
	 * boolean 'and' or a boolean 'or' expression depending on the and
	 * flag. If at least one query is a full query, all queries will instead be evaluated
	 * using intersection when and is true or a union.
	 * 
	 * @param queries The queries to perform
	 * @param and true if this query represents an intersection or a
	 * logical 'and', and false if this query represents a union or
	 * a logical 'or'.
	 * @return A compound query
	 */
	@SuppressWarnings("unchecked")
	public static  IQuery createCompoundQuery(Collection> queries, boolean and) {
		IExpressionFactory factory = ExpressionUtil.getFactory();
		int top = queries.size();
		if (top == 1)
			return (IQuery) queries.iterator().next();

		Class elementClass = (Class) Object.class;
		if (top == 0)
			return QueryUtil. createMatchQuery(elementClass, ExpressionUtil.TRUE_EXPRESSION);

		IExpression[] expressions = new IExpression[top];
		boolean justBooleans = true;
		boolean justContexts = true;
		int idx = 0;
		for (IQuery query : queries) {
			if (query instanceof IMatchQuery)
				justContexts = false;
			else
				justBooleans = false;

			IExpression expr = query.getExpression();
			if (expr == null)
				expr = factory.toExpression(query);

			Class ec = ExpressionQuery.getElementClass(query);
			if (elementClass == null)
				elementClass = ec;
			else if (elementClass != ec) {
				if (elementClass.isAssignableFrom(ec)) {
					if (and)
						// Use most restrictive class
						elementClass = ec;
				} else if (ec.isAssignableFrom(elementClass)) {
					if (!and)
						// Use least restrictive class
						elementClass = ec;
				}
			}
			expressions[idx++] = expr;
		}

		if (justBooleans) {
			IExpression compound = and ? factory.and(expressions) : factory.or(expressions);
			return QueryUtil. createMatchQuery(elementClass, compound);
		}

		if (!justContexts) {
			// Mix of boolean queries and context queries. All must be converted into context then.
			for (idx = 0; idx < expressions.length; ++idx)
				expressions[idx] = makeContextExpression(factory, expressions[idx]);
		}

		IExpression compound = expressions[0];
		for (idx = 1; idx < expressions.length; ++idx)
			compound = and ? factory.intersect(compound, expressions[idx]) : factory.union(compound, expressions[idx]);
		return QueryUtil. createQuery(elementClass, compound);
	}

	/**
	 * Creates a compound query that combines the two queries. If both queries
	 * are candidate match queries, then the queries will be concatenated as a
	 * boolean 'and' or a boolean 'or' expression depending on the and
	 * flag. If at least one query is a full query, all queries will instead be evaluated
	 * using intersection when and is true or a union.
	 * 
	 * @param query1 the first query
	 * @param query2 the second query
	 * @param and true if this query represents an intersection or a
	 * logical 'and', and false if this query represents a union or
	 * a logical 'or'.
	 * @return A compound query
	 */
	public static  IQuery createCompoundQuery(IQuery query1, IQuery query2, boolean and) {
		ArrayList> queries = new ArrayList>(2);
		queries.add(query1);
		queries.add(query2);
		return createCompoundQuery(queries, and);
	}

	/**
	 * Returns a query that matches all {@link InstallableUnit} elements
	 */
	public static IQuery createIUAnyQuery() {
		return ALL_UNITS;
	}

	/**
	 * Creates a new query that will return the members of the
	 * given category.  If the specified {@link IInstallableUnit} 
	 * is not a category, then no installable unit will satisfy the query. 
	 * 
	 * @param category The category
	 * @return A query that returns category members
	 */
	public static IQuery createIUCategoryMemberQuery(IInstallableUnit category) {
		if (QueryUtil.isCategory(category))
			return QueryUtil.createMatchQuery(matchesRequirementsExpression, category.getRequirements());
		return NO_UNITS;
	}

	/**
	 * Creates a query matching every {@link IInstallableUnit} that is a category.
	 * @return The query that matches categories
	 * @since 2.0 
	 */
	public static IQuery createIUCategoryQuery() {
		return createIUPropertyQuery(QueryUtil.PROP_TYPE_CATEGORY, Boolean.TRUE.toString());
	}

	/**
	 * Creates a query matching every {@link IInstallableUnit} that is a group. 
	 * @return a query that matches all groups
	 */
	public static IQuery createIUGroupQuery() {
		return createIUPropertyQuery(PROP_TYPE_GROUP, Boolean.TRUE.toString());
	}

	/**
	 * Creates an {@link IInstallableUnit} that will match all patches.
	 * @return The created query
	 */
	public static IQuery createIUPatchQuery() {
		return createIUPropertyQuery(QueryUtil.PROP_TYPE_PATCH, Boolean.TRUE.toString());
	}

	/**
	 * Creates an {@link IInstallableUnit} that will match all products.
	 * @return The created query
	 * @since 2.2
	 */
	public static IQuery createIUProductQuery() {
		return createIUPropertyQuery(MetadataFactory.InstallableUnitDescription.PROP_TYPE_PRODUCT, Boolean.TRUE.toString());
	}

	/**
	 * Creates a query that searches for {@link IInstallableUnit} instances that have
	 * a property whose value matches the provided value.  If no property name is 
	 * specified, then all {@link IInstallableUnit} instances are accepted.
	 * @param propertyName The key of the property to match or null to match all
	 * @param propertyValue The value of the property. Can be {@link #ANY} to match all values
	 * except null
	 * @return The query matching properties
	 */
	public static IQuery createIUPropertyQuery(String propertyName, String propertyValue) {
		if (propertyName == null)
			return QueryUtil.createMatchQuery(ExpressionUtil.TRUE_EXPRESSION);
		if (propertyValue == null)
			return QueryUtil.createMatchQuery(matchIU_propNull, propertyName);
		if (ANY.equals(propertyValue))
			return QueryUtil.createMatchQuery(matchIU_propAny, propertyName);
		if (Boolean.valueOf(propertyValue).booleanValue())
			return QueryUtil.createMatchQuery(matchIU_propTrue, propertyName);
		return QueryUtil.createMatchQuery(matchIU_propValue, propertyName, propertyValue);
	}

	/**
	 * Creates a query that will match any {@link IInstallableUnit} with the given
	 * id and version.
	 * 
	 * @param versionedId The precise id/version combination that a matching unit must have
	 * @return a query that matches IU's by id and version
	 */
	public static IQuery createIUQuery(IVersionedId versionedId) {
		return createIUQuery(versionedId.getId(), versionedId.getVersion());
	}

	/**
	 * Creates a query that will match any {@link IInstallableUnit} with the given
	 * id, regardless of version.
	 * 
	 * @param id The installable unit id to match, or null to match any id
	 * @return a query that matches IU's by id
	 */
	public static IQuery createIUQuery(String id) {
		return id == null ? ALL_UNITS : QueryUtil.createMatchQuery(matchIU_ID, id);
	}

	/**
	 * Creates a query that will match any {@link IInstallableUnit} with the given
	 * id and version.
	 * 
	 * @param id The installable unit id to match, or null to match any id
	 * @param version The precise version that a matching unit must have or null
	 * to match any version
	 * @return a query that matches IU's by id and version
	 */
	public static IQuery createIUQuery(String id, Version version) {
		if (version == null || version.equals(Version.emptyVersion))
			return createIUQuery(id);
		if (id == null)
			return QueryUtil.createMatchQuery(matchIU_Version, version);
		return QueryUtil.createMatchQuery(matchIU_IDAndVersion, id, version);
	}

	/**
	 * Creates a query that will match any {@link IInstallableUnit} with the given
	 * id, and whose version falls in the provided range.
	 * 
	 * @param id The installable unit id to match, or null to match any id
	 * @param range The version range to match or null to match any range.
	 * @return a query that matches IU's by id and range
	 */
	public static IQuery createIUQuery(String id, VersionRange range) {
		if (range == null || range.equals(VersionRange.emptyRange))
			return createIUQuery(id);
		if (id == null)
			return QueryUtil.createMatchQuery(matchIU_Range, range);
		return QueryUtil.createMatchQuery(matchIU_IDAndRange, id, range);
	}

	/**
	 * Creates a query that returns the latest version for each unique id of an {@link IVersionedId}.  
	 * All other elements are discarded.
	 * @return A query matching the latest version for each id.
	 */
	public static IQuery createLatestIUQuery() {
		return QueryUtil.createQuery(ExpressionUtil.getFactory().latest(ExpressionFactory.EVERYTHING));
	}

	/**
	 * Creates a query that returns the latest version for each unique id of an {@link IVersionedId}
	 * from the collection produced by query. 
	 * All other elements are discarded.
	 * @param query The query that precedes the latest query when evaluating.
	 * @return A query matching the latest version for each id.
	 */
	public static  IQuery createLatestQuery(IQuery query) {
		IContextExpression ctxExpr = ExpressionQuery.createExpression(query);
		IExpressionFactory factory = ExpressionUtil.getFactory();
		@SuppressWarnings("unchecked")
		Class elementClass = (Class) IVersionedId.class;
		return QueryUtil.createQuery(elementClass, factory.latest(((ContextExpression) ctxExpr).operand), ctxExpr.getParameters());
	}

	/**
	 * Creates a limit query that can be used to limit the number of query results returned.  Once
	 * the limit is reached, the query is terminated.
	 * @param query The query that should be limited
	 * @param limit A positive integer denoting the limit
	 * @return A limited query
	 * @since 2.0
	 */
	public static  IQuery createLimitQuery(IQuery query, int limit) {
		IContextExpression ctxExpr = ExpressionQuery.createExpression(query);
		IExpressionFactory factory = ExpressionUtil.getFactory();
		return QueryUtil.createQuery(ExpressionQuery.getElementClass(query), factory.limit(((ContextExpression) ctxExpr).operand, limit), ctxExpr.getParameters());
	}

	/**
	 * Creates an {@link IInstallableUnit} query that will iterate over all candidates and discriminate by
	 * applying the boolean matchExpression on each candidate.
	 * @param matchExpression The boolean expression used for filtering one candidate
	 * @param parameters Values for parameter substitution
	 * @return The created query
	 */
	public static IQuery createMatchQuery(IExpression matchExpression, Object... parameters) {
		return new ExpressionMatchQuery(IInstallableUnit.class, matchExpression, parameters);
	}

	/**
	 * Parses the matchExpression and creates an {@link IInstallableUnit} query that will
	 * iterate over all candidates and discriminate by applying the boolean matchExpression
	 * on each candidate.
	 * @param matchExpression The boolean expression used for filtering one candidate
	 * @param parameters Values for parameter substitution
	 * @return The created query
	 */
	public static IQuery createMatchQuery(String matchExpression, Object... parameters) {
		return new ExpressionMatchQuery(IInstallableUnit.class, matchExpression, parameters);
	}

	/**
	 * Creates an query that will iterate over all candidates and discriminate all
	 * candidates that are not instances of matchinClass> or for which
	 * the boolean matchExpression returns false.
	 * @param matchingClass The class that matching candidates must be an instance of
	 * @param matchExpression The boolean expression used for filtering one candidate
	 * @param parameters Values for parameter substitution
	 * @return The created query
	 */
	public static  IQuery createMatchQuery(Class matchingClass, IExpression matchExpression, Object... parameters) {
		return new ExpressionMatchQuery(matchingClass, matchExpression, parameters);
	}

	/**
	 * Parses the matchExpression and creates an query that will iterate over
	 * all candidates and discriminate all candidates that are not instances of
	 * matchinClass> or for which the boolean matchExpression
	 * returns false.
	 * @param matchingClass The class that matching candidates must be an instance of
	 * @param matchExpression The boolean expression used for filtering one candidate
	 * @param parameters Values for parameter substitution
	 * @return The created query
	 */
	public static  IQuery createMatchQuery(Class matchingClass, String matchExpression, Object... parameters) {
		return new ExpressionMatchQuery(matchingClass, matchExpression, parameters);
	}

	/**
	 * 

Creates a piped query based on the provided input queries.

*

A pipe is a composite query in which each sub-query is executed in succession. * The results from the ith sub-query are piped as input into the i+1th sub-query. The * query will short-circuit if any query returns an empty result set.

* * @param queries the ordered list of queries to perform * @return A query pipe */ @SuppressWarnings("unchecked") public static IQuery createPipeQuery(Collection> queries) { IExpressionFactory factory = ExpressionUtil.getFactory(); int top = queries.size(); IExpression[] expressions = new IExpression[top]; int idx = 0; for (IQuery query : queries) { IExpression expr = query.getExpression(); if (expr == null) expr = factory.toExpression(query); expressions[idx++] = expr; } IExpression pipe = factory.pipe(expressions); VariableFinder finder = new VariableFinder(ExpressionFactory.EVERYTHING); pipe.accept(finder); return finder.isFound() ? QueryUtil. createQuery((Class) Object.class, pipe) : QueryUtil. createMatchQuery((Class) Object.class, pipe); } /** *

Creates a piped query based on the provided input queries.

*

A pipe is a composite query in which each sub-query is executed in succession. * The results from the ith sub-query are piped as input into the i+1th sub-query. The * query will short-circuit if any query returns an empty result set.

* * @param query1 the first query * @param query2 the second query * @return A query pipe */ public static IQuery createPipeQuery(IQuery query1, IQuery query2) { ArrayList> queries = new ArrayList>(2); queries.add(query1); queries.add(query2); return createPipeQuery(queries); } /** * Creates an {@link IInstallableUnit} query based on an expression that * uses all candidates as input. * @param expression The query expression * @param parameters Values for parameter substitution * @return The created query */ public static IQuery createQuery(IExpression expression, Object... parameters) { return new ExpressionQuery(IInstallableUnit.class, expression, parameters); } /** * Parses the expression and creates an {@link IInstallableUnit} query. The * expression is expected to use all candidates as input. * @param expression The query expression * @param parameters Values for parameter substitution * @return The created query */ public static IQuery createQuery(String expression, Object... parameters) { return new ExpressionQuery(IInstallableUnit.class, expression, parameters); } /** * Creates a query that will limit the result to instances of the matchinClass. The * expression is expected to use all candidates as input. * @param matchingClass The class used as discriminator for the result * @param expression The query expression * @param parameters Values for parameter substitution * @return The created query */ public static IQuery createQuery(Class matchingClass, IExpression expression, Object... parameters) { return new ExpressionQuery(matchingClass, expression, parameters); } /** * Parses the expression and creates a query that will limit the result * to instances of the matchinClass. The expression is expected * to use all candidates as input. * @param matchingClass The class used as discriminator for the result * @param expression The query expression * @param parameters Values for parameter substitution * @return The created query */ public static IQuery createQuery(Class matchingClass, String expression, Object... parameters) { return new ExpressionQuery(matchingClass, expression, parameters); } /** * Test if the {@link IInstallableUnit} is a category. * @param iu the element being tested. * @return true if the parameter is a category. */ public static boolean isCategory(IInstallableUnit iu) { String value = iu.getProperty(PROP_TYPE_CATEGORY); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Test if the {@link IInstallableUnit} is a fragment. * @param iu the element being tested. * @return true if the parameter is a fragment. */ public static boolean isFragment(IInstallableUnit iu) { return iu instanceof IInstallableUnitFragment; } /** * Test if the {@link IInstallableUnit} is a group. * @param iu the element being tested. * @return true if the parameter is a group. */ public static boolean isGroup(IInstallableUnit iu) { String value = iu.getProperty(PROP_TYPE_GROUP); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Test if the {@link IInstallableUnit} is a product. * @param iu the element being tested. * @return true if the parameter is a group. * @since 2.2 */ public static boolean isProduct(IInstallableUnit iu) { String value = iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_PRODUCT); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Test if the {@link IInstallableUnit} is a patch. * @param iu the element being tested. * @return true if the parameter is a patch. */ public static boolean isPatch(IInstallableUnit iu) { String value = iu.getProperty(PROP_TYPE_PATCH); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } private static IExpression makeContextExpression(IExpressionFactory factory, IExpression expr) { VariableFinder finder = new VariableFinder(ExpressionFactory.EVERYTHING); expr.accept(finder); if (!finder.isFound()) expr = factory.select(ExpressionFactory.EVERYTHING, factory.lambda(ExpressionFactory.THIS, expr)); return expr; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy