blob: 621838be468239c666ff289c6fde8355481cec48 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 EclipseSource 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:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.equinox.p2.query;
import java.util.*;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
import org.eclipse.equinox.internal.p2.metadata.expression.CompoundIterator;
import org.eclipse.equinox.internal.p2.metadata.index.CompoundIndex;
import org.eclipse.equinox.internal.p2.metadata.index.IndexProvider;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.KeyWithLocale;
import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext;
import org.eclipse.equinox.p2.metadata.expression.IExpression;
import org.eclipse.equinox.p2.metadata.index.IIndex;
import org.eclipse.equinox.p2.metadata.index.IIndexProvider;
/**
* A queryable that holds a number of other IQueryables and provides
* a mechanism for querying the entire set.
* @since 2.0
*/
public final class CompoundQueryable<T> extends IndexProvider<T> {
static class PassThroughIndex<T> implements IIndex<T> {
private final Iterator<T> iterator;
public PassThroughIndex(Iterator<T> iterator) {
this.iterator = iterator;
}
public Iterator<T> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr) {
return iterator;
}
}
private IQueryable<T>[] queryables;
public CompoundQueryable(IQueryable<T>[] queryables) {
this.queryables = queryables;
}
/**
* Creates a queryable that combines the given collection of input queryables
*
* @param queryables The collection of queryables to be combined
*/
CompoundQueryable(Collection<? extends IQueryable<T>> queryables) {
// don't suppress the warning as it will cause warnings in the official build
// see bug 423628. Write this without unchecked conversion.
this(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")
CompoundQueryable(IQueryable<T> query1, IQueryable<T> query2) {
this(new IQueryable[] {query1, query2});
}
public IIndex<T> getIndex(String memberName) {
// Check that at least one of the queryable can present an index
// for the given member.
boolean found = false;
for (IQueryable<T> queryable : queryables) {
if (queryable instanceof IIndexProvider<?>) {
@SuppressWarnings("unchecked")
IIndexProvider<T> ip = (IIndexProvider<T>) queryable;
if (ip.getIndex(memberName) != null) {
found = true;
break;
}
}
}
if (!found)
// Nobody had an index for this member
return null;
ArrayList<IIndex<T>> indexes = new ArrayList<IIndex<T>>(queryables.length);
for (IQueryable<T> queryable : queryables) {
if (queryable instanceof IIndexProvider<?>) {
@SuppressWarnings("unchecked")
IIndexProvider<T> ip = (IIndexProvider<T>) queryable;
IIndex<T> index = ip.getIndex(memberName);
if (index != null)
indexes.add(index);
else
indexes.add(new PassThroughIndex<T>(ip.everything()));
} else {
indexes.add(new PassThroughIndex<T>(getIteratorFromQueryable(queryable)));
}
}
return indexes.size() == 1 ? indexes.get(0) : new CompoundIndex<T>(indexes);
}
public Iterator<T> everything() {
if (queryables.length == 0)
return Collections.<T> emptySet().iterator();
if (queryables.length == 1)
return getIteratorFromQueryable(queryables[0]);
ArrayList<Iterator<T>> iterators = new ArrayList<Iterator<T>>(queryables.length);
for (IQueryable<T> queryable : queryables)
iterators.add(getIteratorFromQueryable(queryable));
return new CompoundIterator<T>(iterators.iterator());
}
public Object getManagedProperty(Object client, String memberName, Object key) {
for (IQueryable<T> queryable : queryables) {
if (queryable instanceof IIndexProvider<?>) {
@SuppressWarnings("unchecked")
IIndexProvider<T> ip = (IIndexProvider<T>) queryable;
Object value = ip.getManagedProperty(client, memberName, key);
if (value != null)
return value;
}
}
// When asked for translatedProperties we should return from the IU when the property is not found.
if (client instanceof IInstallableUnit && memberName.equals(InstallableUnit.MEMBER_TRANSLATED_PROPERTIES)) {
IInstallableUnit iu = (IInstallableUnit) client;
return key instanceof KeyWithLocale ? iu.getProperty(((KeyWithLocale) key).getKey()) : iu.getProperty(key.toString());
}
return null;
}
static class IteratorCapture<T> implements IQuery<T> {
private Iterator<T> capturedIterator;
public IQueryResult<T> perform(Iterator<T> iterator) {
capturedIterator = iterator;
return Collector.emptyCollector();
}
public IExpression getExpression() {
return null;
}
Iterator<T> getCapturedIterator() {
return capturedIterator == null ? Collections.<T> emptySet().iterator() : capturedIterator;
}
}
private static <T> Iterator<T> getIteratorFromQueryable(IQueryable<T> queryable) {
if (queryable instanceof IIndexProvider<?>) {
@SuppressWarnings("unchecked")
IIndexProvider<T> ip = (IIndexProvider<T>) queryable;
return ip.everything();
}
IteratorCapture<T> capture = new IteratorCapture<T>();
queryable.query(capture, new NullProgressMonitor());
return capture.getCapturedIterator();
}
}