diff options
author | Thomas Hallgren | 2010-02-19 12:13:19 +0000 |
---|---|---|
committer | Thomas Hallgren | 2010-02-19 12:13:19 +0000 |
commit | 3a4abd5c6deca5395ea24bb742ab53fa21427f85 (patch) | |
tree | 9eb424ba5b281990970f584088d4ceef5bf05111 | |
parent | 273e205c6904675b1b1314b6f4df5f9e962735b5 (diff) | |
download | rt.equinox.p2-3a4abd5c6deca5395ea24bb742ab53fa21427f85.tar.gz rt.equinox.p2-3a4abd5c6deca5395ea24bb742ab53fa21427f85.tar.xz rt.equinox.p2-3a4abd5c6deca5395ea24bb742ab53fa21427f85.zip |
302201 : Unify the two query approaches used in p2
97 files changed, 1651 insertions, 703 deletions
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/FlatteningIterator.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/FlatteningIterator.java deleted file mode 100644 index 1035f1420..000000000 --- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/FlatteningIterator.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 IBM Corporation 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.equinox.internal.p2.artifact.repository; - -import java.util.*; - -/** - * An iterator over values that are provided by iterating over collections. - */ -public class FlatteningIterator<T> implements Iterator<T> { - private static final Object NO_ELEMENT = new Object(); - private final Iterator<? extends Collection<T>> collectionIterator; - private Iterator<T> currentIterator; - - private T nextObject = noElement(); - - public FlatteningIterator(Iterator<? extends Collection<T>> collectionIterator) { - this.collectionIterator = collectionIterator; - } - - public boolean hasNext() { - return positionNext(); - } - - public T next() { - if (!positionNext()) - throw new NoSuchElementException(); - - T nxt = nextObject; - nextObject = noElement(); - return nxt; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - private boolean positionNext() { - if (nextObject != NO_ELEMENT) - return true; - - while (currentIterator == null || !currentIterator.hasNext()) { - if (!collectionIterator.hasNext()) - return false; - currentIterator = collectionIterator.next().iterator(); - } - nextObject = currentIterator.next(); - return true; - } - - @SuppressWarnings("unchecked") - private static <T> T noElement() { - return (T) NO_ELEMENT; - } -}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/KeyIndex.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/KeyIndex.java new file mode 100644 index 000000000..445543289 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/KeyIndex.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.artifact.repository.simple; + +import java.util.*; +import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; +import org.eclipse.equinox.internal.p2.metadata.ArtifactKey; +import org.eclipse.equinox.internal.p2.metadata.index.Index; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.expression.IExpression; + +/** + * An index that maps id to IArtifactKey + */ +public class KeyIndex extends Index<IArtifactKey> { + // Memory conserving map. Stores either String -> IArtifactKey + // or String -> IArtifactKey[] + // A stored array is always length >= 2. + private final Map<String, Object> artifactMap; + + public KeyIndex(Collection<IArtifactKey> artifactKeys) { + artifactMap = new HashMap<String, Object>(artifactKeys.size()); + for (IArtifactKey ak : artifactKeys) { + Object prev = artifactMap.put(ak.getId(), ak); + if (prev != null) { + if (prev instanceof IArtifactKey) + artifactMap.put(ak.getId(), new IArtifactKey[] {(IArtifactKey) prev, ak}); + else { + IArtifactKey[] prevArr = (IArtifactKey[]) prev; + IArtifactKey[] nxtArr = new IArtifactKey[prevArr.length + 1]; + System.arraycopy(prevArr, 0, nxtArr, 0, prevArr.length); + nxtArr[prevArr.length] = ak; + artifactMap.put(ak.getId(), nxtArr); + } + } + } + } + + public Iterator<IArtifactKey> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr) { + Object queriedKeys = getQueriedIDs(ctx, variable, ArtifactKey.MEMBER_ID, booleanExpr, null); + if (queriedKeys == null) + return null; + + Collection<IArtifactKey> collector = null; + if (queriedKeys.getClass().isArray()) { + Object[] keyArr = (Object[]) queriedKeys; + int idx = keyArr.length; + while (--idx >= 0) { + Object v = artifactMap.get(keyArr[idx]); + if (v == null) + continue; + if (collector == null) + collector = new ArrayList<IArtifactKey>(); + if (v instanceof IArtifactKey) + collector.add((IArtifactKey) v); + else { + IArtifactKey[] akArr = (IArtifactKey[]) v; + for (IArtifactKey ak : akArr) + collector.add(ak); + } + } + if (collector == null) + collector = CollectionUtils.emptySet(); + } else { + Object v = artifactMap.get(queriedKeys); + if (v == null) + collector = CollectionUtils.emptySet(); + else if (v instanceof IArtifactKey) + collector = Collections.singleton((IArtifactKey) v); + else + collector = CollectionUtils.unmodifiableList((IArtifactKey[]) v); + } + return collector.iterator(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/SimpleArtifactRepository.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/SimpleArtifactRepository.java index 674df3b9d..42d5acbf2 100644 --- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/SimpleArtifactRepository.java +++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/simple/SimpleArtifactRepository.java @@ -24,6 +24,8 @@ import org.eclipse.equinox.internal.p2.artifact.processors.md5.MD5Verifier; import org.eclipse.equinox.internal.p2.artifact.repository.*; import org.eclipse.equinox.internal.p2.artifact.repository.Messages; import org.eclipse.equinox.internal.p2.core.helpers.FileUtils; +import org.eclipse.equinox.internal.p2.metadata.ArtifactKey; +import org.eclipse.equinox.internal.p2.metadata.expression.CompoundIterator; import org.eclipse.equinox.internal.p2.repository.RepositoryTransport; import org.eclipse.equinox.internal.p2.repository.Transport; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.processing.*; @@ -31,6 +33,7 @@ import org.eclipse.equinox.internal.provisional.p2.repository.IStateful; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.index.*; import org.eclipse.equinox.p2.query.*; import org.eclipse.equinox.p2.repository.IRepository; import org.eclipse.equinox.p2.repository.artifact.*; @@ -38,7 +41,7 @@ import org.eclipse.equinox.p2.repository.artifact.spi.AbstractArtifactRepository import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor; import org.eclipse.osgi.util.NLS; -public class SimpleArtifactRepository extends AbstractArtifactRepository implements IArtifactRepository, IFileArtifactRepository { +public class SimpleArtifactRepository extends AbstractArtifactRepository implements IArtifactRepository, IFileArtifactRepository, IIndexProvider<IArtifactKey> { /** * A boolean property controlling whether mirroring is enabled. */ @@ -204,9 +207,10 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme /** * Map<IArtifactKey,List<IArtifactDescriptor>> containing the index of artifacts in the repository. */ - protected Map<IArtifactKey, List<IArtifactDescriptor>> artifactMap = new HashMap<IArtifactKey, List<IArtifactDescriptor>>(); + protected final Map<IArtifactKey, List<IArtifactDescriptor>> artifactMap = new HashMap<IArtifactKey, List<IArtifactDescriptor>>(); private transient BlobStore blobStore; transient private Mapper mapper = new Mapper(); + private KeyIndex keyIndex; static final private String PUBLISH_PACK_FILES_AS_SIBLINGS = "publishPackFilesAsSiblings"; //$NON-NLS-1$ @@ -271,6 +275,7 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme if (descriptors == null) { descriptors = new ArrayList<IArtifactDescriptor>(); artifactMap.put(key, descriptors); + keyIndex = null; } descriptors.add(descriptor); } @@ -282,8 +287,10 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme return; descriptors.remove(descriptor); - if (descriptors.isEmpty()) + if (descriptors.isEmpty()) { artifactMap.remove(key); + keyIndex = null; + } } public SimpleArtifactRepository(IProvisioningAgent agent, String repositoryName, URI location, Map<String, String> properties) { @@ -906,7 +913,7 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme public void save() { if (disableSave) return; - boolean compress = "true".equalsIgnoreCase((String) properties.get(PROP_COMPRESSED)); //$NON-NLS-1$ + boolean compress = "true".equalsIgnoreCase(properties.get(PROP_COMPRESSED)); //$NON-NLS-1$ save(compress); } @@ -988,13 +995,17 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme return new IQueryable<IArtifactDescriptor>() { public IQueryResult<IArtifactDescriptor> query(IQuery<IArtifactDescriptor> query, IProgressMonitor monitor) { - return query.perform(new FlatteningIterator<IArtifactDescriptor>(descs.iterator())); + return query.perform(new CompoundIterator<IArtifactDescriptor>(descs.iterator())); } }; } - public IQueryResult<IArtifactKey> query(IQuery<IArtifactKey> query, IProgressMonitor monitor) { - return query.perform(artifactMap.keySet().iterator()); + public synchronized IQueryResult<IArtifactKey> query(IQuery<IArtifactKey> query, IProgressMonitor monitor) { + return query instanceof IQueryWithIndex<?> ? ((IQueryWithIndex<IArtifactKey>) query).perform(this) : query.perform(artifactMap.keySet().iterator()); + } + + public Iterator<IArtifactKey> everything() { + return artifactMap.keySet().iterator(); } public IStatus executeBatch(Runnable runnable) { @@ -1021,4 +1032,13 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme result = Status.OK_STATUS; return result; } + + public synchronized IIndex<IArtifactKey> getIndex(String memberName) { + if (ArtifactKey.MEMBER_ID.equals(memberName)) { + if (keyIndex == null) + keyIndex = new KeyIndex(artifactMap.keySet()); + return keyIndex; + } + return null; + } } diff --git a/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/Application.java b/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/Application.java index 011a67b10..673cd25c7 100644 --- a/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/Application.java +++ b/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/Application.java @@ -387,7 +387,7 @@ public class Application implements IApplication { IProfile profile = initializeProfile(); query = new InstallableUnitQuery(root, version == null ? VersionRange.emptyRange : new VersionRange(version, true, version, true)); - roots = collectRootIUs(metadataRepositoryLocations, new PipedQuery<IInstallableUnit>(query, new LatestIUVersionQuery<IInstallableUnit>())); + roots = collectRootIUs(metadataRepositoryLocations, new LatestIUVersionQuery<IInstallableUnit>(query)); if (roots.isEmpty()) roots = profile.query(query, new NullProgressMonitor()); if (roots.isEmpty()) { diff --git a/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/DirectorApplication.java b/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/DirectorApplication.java index 860032450..c460f6cff 100644 --- a/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/DirectorApplication.java +++ b/bundles/org.eclipse.equinox.p2.director.app/src/org/eclipse/equinox/internal/p2/director/app/DirectorApplication.java @@ -13,8 +13,6 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.director.app; -import org.eclipse.equinox.p2.planner.IPlanner; - import java.io.*; import java.net.URI; import java.net.URISyntaxException; @@ -33,6 +31,7 @@ import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.metadata.*; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; +import org.eclipse.equinox.p2.planner.IPlanner; import org.eclipse.equinox.p2.planner.IProfileChangeRequest; import org.eclipse.equinox.p2.query.*; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; @@ -255,7 +254,7 @@ public class DirectorApplication implements IApplication { IQuery<IInstallableUnit> query = new InstallableUnitQuery(rootName.getId(), Version.emptyVersion.equals(v) ? VersionRange.emptyRange : new VersionRange(v, true, v, true)); IQueryResult<IInstallableUnit> roots = null; if (forInstall) - roots = collectRootIUs(new PipedQuery<IInstallableUnit>(query, new LatestIUVersionQuery<IInstallableUnit>())); + roots = collectRootIUs(new LatestIUVersionQuery<IInstallableUnit>(query)); if (roots == null || roots.isEmpty()) roots = profile.query(query, new NullProgressMonitor()); diff --git a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/QueryableArray.java b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/QueryableArray.java index d2208d6b5..fcb4bef92 100644 --- a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/QueryableArray.java +++ b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/QueryableArray.java @@ -10,79 +10,38 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.director; -import java.util.*; +import java.util.Iterator; +import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.equinox.internal.p2.metadata.RequiredCapability; +import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.metadata.index.CapabilityIndex; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.IProvidedCapability; -import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; -import org.eclipse.equinox.p2.metadata.query.ExpressionQuery; +import org.eclipse.equinox.p2.metadata.index.*; import org.eclipse.equinox.p2.query.*; -public class QueryableArray implements IQueryable<IInstallableUnit> { +public class QueryableArray implements IQueryable<IInstallableUnit>, IIndexProvider<IInstallableUnit> { private final List<IInstallableUnit> dataSet; - private Map<String, List<IInstallableUnit>> namedCapabilityIndex; + private IIndex<IInstallableUnit> capabilityIndex; public QueryableArray(IInstallableUnit[] ius) { - dataSet = Arrays.asList(ius); + dataSet = CollectionUtils.unmodifiableList(ius); } - public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) { - if (query instanceof ExpressionQuery<?>) - return queryCapability((ExpressionQuery<IInstallableUnit>) query, new Collector<IInstallableUnit>(), monitor); - return query.perform(dataSet.iterator()); + public synchronized IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) { + return query instanceof IQueryWithIndex<?> ? ((IQueryWithIndex<IInstallableUnit>) query).perform(this) : query.perform(dataSet.iterator()); } - private Collector<IInstallableUnit> queryCapability(ExpressionQuery<IInstallableUnit> query, Collector<IInstallableUnit> collector, IProgressMonitor monitor) { - generateNamedCapabilityIndex(); - - Collection<IInstallableUnit> resultIUs = null; - Collection<IInstallableUnit> matchingIUs = findMatchingIUs(query.getExpression()); - if (matchingIUs == null) - return collector; - if (resultIUs == null) - resultIUs = matchingIUs; - else - resultIUs.retainAll(matchingIUs); - - if (resultIUs != null) - for (Iterator<IInstallableUnit> iterator = resultIUs.iterator(); iterator.hasNext();) - collector.accept(iterator.next()); - - return collector; + public Iterator<IInstallableUnit> everything() { + return dataSet.iterator(); } - private Collection<IInstallableUnit> findMatchingIUs(IMatchExpression<IInstallableUnit> requirementMatch) { - // TODO: This is a hack. Should be replaced by use of proper indexes - List<IInstallableUnit> ius = namedCapabilityIndex.get(RequiredCapability.extractName(requirementMatch)); - if (ius == null) - return null; - - Set<IInstallableUnit> matchingIUs = new HashSet<IInstallableUnit>(); - for (IInstallableUnit iu : ius) { - if (requirementMatch.isMatch(iu)) - matchingIUs.add(iu); - } - return matchingIUs; - } - - private void generateNamedCapabilityIndex() { - if (namedCapabilityIndex != null) - return; - - namedCapabilityIndex = new HashMap<String, List<IInstallableUnit>>(); - for (IInstallableUnit iu : dataSet) { - - Collection<IProvidedCapability> providedCapabilities = iu.getProvidedCapabilities(); - for (IProvidedCapability pc : providedCapabilities) { - String name = pc.getName(); - List<IInstallableUnit> ius = namedCapabilityIndex.get(name); - if (ius == null) { - ius = new ArrayList<IInstallableUnit>(5); - namedCapabilityIndex.put(name, ius); - } - ius.add(iu); - } + public synchronized IIndex<IInstallableUnit> getIndex(String memberName) { + if (InstallableUnit.MEMBER_PROVIDED_CAPABILITIES.equals(memberName)) { + if (capabilityIndex == null) + capabilityIndex = new CapabilityIndex(dataSet.iterator()); + return capabilityIndex; } + return null; } } diff --git a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/SimplePlanner.java b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/SimplePlanner.java index 0944f9ee4..3f1779aee 100644 --- a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/SimplePlanner.java +++ b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/SimplePlanner.java @@ -114,7 +114,7 @@ public class SimplePlanner implements IPlanner { } //Compute the side effect changes (e.g. things installed optionally going away) - Iterator<IInstallableUnit> includedIUs = changeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, null), null).iterator(); + Iterator<IInstallableUnit> includedIUs = changeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, IUProfilePropertyQuery.ANY), null).iterator(); Map<IInstallableUnit, RequestStatus> sideEffectStatus = new HashMap<IInstallableUnit, RequestStatus>(); while (includedIUs.hasNext()) { IInstallableUnit removal = includedIUs.next(); @@ -205,8 +205,8 @@ public class SimplePlanner implements IPlanner { } public static Collection<IInstallableUnit> findPlannerMarkedIUs(final IProfile profile) { - IQuery<IInstallableUnit> markerQuery = new IUProfilePropertyQuery(INCLUSION_RULES, null); - return profile.query(markerQuery, null).toSet(); + IQuery<IInstallableUnit> markerQuery = new IUProfilePropertyQuery(INCLUSION_RULES, IUProfilePropertyQuery.ANY); + return profile.query(markerQuery, null).unmodifiableSet(); } public static Dictionary<String, String> createSelectionContext(Map<String, String> properties) { @@ -652,7 +652,7 @@ public class SimplePlanner implements IPlanner { //It returns at index 0 a meta IU representing everything that needs to be installed //It returns at index 1 all the IUs that are in the profile after the removal have been done, but before the addition have been done private Object[] updatePlannerInfo(ProfileChangeRequest profileChangeRequest, ProvisioningContext context) { - IQueryResult<IInstallableUnit> alreadyInstalled = profileChangeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, null), null); + IQueryResult<IInstallableUnit> alreadyInstalled = profileChangeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, IUProfilePropertyQuery.ANY), null); Collection<IInstallableUnit> additionRequested = profileChangeRequest.getAdditions(); Collection<IInstallableUnit> removalRequested = profileChangeRequest.getRemovals(); diff --git a/bundles/org.eclipse.equinox.p2.directorywatcher/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.directorywatcher/META-INF/MANIFEST.MF index b38923555..f81d0dbcc 100644 --- a/bundles/org.eclipse.equinox.p2.directorywatcher/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.directorywatcher/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-Version: 1.0.100.qualifier Import-Package: org.eclipse.equinox.internal.p2.artifact.repository, org.eclipse.equinox.internal.p2.artifact.repository.simple, org.eclipse.equinox.internal.p2.core.helpers, + org.eclipse.equinox.internal.p2.metadata.expression, org.eclipse.equinox.internal.p2.update, org.eclipse.equinox.internal.provisional.p2.core, org.eclipse.equinox.internal.provisional.p2.metadata, diff --git a/bundles/org.eclipse.equinox.p2.directorywatcher/src/org/eclipse/equinox/internal/provisional/p2/directorywatcher/CachingArtifactRepository.java b/bundles/org.eclipse.equinox.p2.directorywatcher/src/org/eclipse/equinox/internal/provisional/p2/directorywatcher/CachingArtifactRepository.java index 38520507b..ac8a55a41 100644 --- a/bundles/org.eclipse.equinox.p2.directorywatcher/src/org/eclipse/equinox/internal/provisional/p2/directorywatcher/CachingArtifactRepository.java +++ b/bundles/org.eclipse.equinox.p2.directorywatcher/src/org/eclipse/equinox/internal/provisional/p2/directorywatcher/CachingArtifactRepository.java @@ -14,7 +14,7 @@ import java.io.OutputStream; import java.net.URI; import java.util.*; import org.eclipse.core.runtime.*; -import org.eclipse.equinox.internal.p2.artifact.repository.FlatteningIterator; +import org.eclipse.equinox.internal.p2.metadata.expression.CompoundIterator; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.query.*; @@ -244,7 +244,7 @@ public class CachingArtifactRepository implements IArtifactRepository, IFileArti final Collection<List<IArtifactDescriptor>> descs = artifactMap.values(); IQueryable<IArtifactDescriptor> cached = new IQueryable<IArtifactDescriptor>() { public IQueryResult<IArtifactDescriptor> query(IQuery<IArtifactDescriptor> query, IProgressMonitor monitor) { - return query.perform(new FlatteningIterator<IArtifactDescriptor>(descs.iterator())); + return query.perform(new CompoundIterator<IArtifactDescriptor>(descs.iterator())); } }; diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/IUProfilePropertyQuery.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/IUProfilePropertyQuery.java index 84437a6f6..7f2a32150 100644 --- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/IUProfilePropertyQuery.java +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/IUProfilePropertyQuery.java @@ -10,16 +10,20 @@ *******************************************************************************/ package org.eclipse.equinox.p2.engine.query; -import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.query.MatchQuery; /** * A query that searches for {@link IInstallableUnit} instances that have * a property associated with the specified profile, whose value matches the provided value. * @since 2.0 */ -public class IUProfilePropertyQuery extends IUPropertyQuery { +public class IUProfilePropertyQuery extends MatchQuery<IInstallableUnit> { + public static final String ANY = "*"; //$NON-NLS-1$ + + private final String propertyName; + private final String propertyValue; private IProfile profile; /** @@ -34,14 +38,19 @@ public class IUProfilePropertyQuery extends IUPropertyQuery { * Because the queryable for this query is typically the profile * instance, we use a reference to the profile rather than the * profile id for performance reasons. + * @param propertyName The name of the property to match + * @param propertyValue The value to compare to. A value of "*" means any value. */ public IUProfilePropertyQuery(String propertyName, String propertyValue) { - super(propertyName, propertyValue); + this.propertyName = propertyName; + this.propertyValue = propertyValue; } - protected String getProperty(IInstallableUnit iu, String name) { + @Override + public boolean isMatch(IInstallableUnit candidate) { if (profile == null) - return null; - return profile.getInstallableUnitProperty(iu, name); + return false; + String foundValue = profile.getInstallableUnitProperty(candidate, propertyName); + return foundValue == null ? propertyValue == null : (ANY.equals(propertyValue) || foundValue.equals(propertyValue)); } } diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/UserVisibleRootQuery.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/UserVisibleRootQuery.java index 20ea0d011..d2c3318ad 100644 --- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/UserVisibleRootQuery.java +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/query/UserVisibleRootQuery.java @@ -13,7 +13,6 @@ package org.eclipse.equinox.p2.engine.query; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; - /** * A query matching all the {@link IInstallableUnit}s that are marked visible to the user. * @since 2.0 @@ -32,8 +31,6 @@ public class UserVisibleRootQuery extends IUProfilePropertyQuery { */ public static boolean isUserVisible(IInstallableUnit iu, IProfile profile) { String value = profile.getInstallableUnitProperty(iu, IProfile.PROP_PROFILE_ROOT_IU); - if (value != null && (value.equals(Boolean.TRUE.toString()))) - return true; - return false; + return Boolean.valueOf(value).booleanValue(); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/internal/provisional/p2/metadata/generator/Generator.java b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/internal/provisional/p2/metadata/generator/Generator.java index 81cfd9e37..772f1887c 100644 --- a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/internal/provisional/p2/metadata/generator/Generator.java +++ b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/internal/provisional/p2/metadata/generator/Generator.java @@ -33,7 +33,8 @@ import org.eclipse.equinox.p2.metadata.*; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; -import org.eclipse.equinox.p2.query.*; +import org.eclipse.equinox.p2.query.IQuery; +import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.repository.IRepository; import org.eclipse.equinox.p2.repository.artifact.*; import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor; @@ -189,7 +190,7 @@ public class Generator { GeneratorResult productContents = new GeneratorResult(); ProductQuery productQuery = new ProductQuery(productFile, info.getFlavor(), result.configurationIUs, info.getVersionAdvice()); - PipedQuery query = new PipedQuery(new IQuery[] {productQuery, new LatestIUVersionQuery()}); + IQuery query = new LatestIUVersionQuery(productQuery); IQueryResult queryResult = info.getMetadataRepository().query(query, null); for (Iterator iterator = queryResult.iterator(); iterator.hasNext();) { productContents.rootIUs.add(iterator.next()); diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF index fcca9dedf..072902636 100644 --- a/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF @@ -19,6 +19,7 @@ Import-Package: javax.xml.parsers, org.eclipse.equinox.app;resolution:=optional, org.eclipse.equinox.internal.p2.core.helpers, org.eclipse.equinox.internal.p2.metadata, + org.eclipse.equinox.internal.p2.metadata.index, org.eclipse.equinox.internal.p2.persistence, org.eclipse.equinox.internal.p2.repository, org.eclipse.equinox.internal.p2.repository.helpers, @@ -29,6 +30,7 @@ Import-Package: javax.xml.parsers, org.eclipse.equinox.p2.core.spi, org.eclipse.equinox.p2.metadata, org.eclipse.equinox.p2.metadata.expression, + org.eclipse.equinox.p2.metadata.index, org.eclipse.equinox.p2.metadata.query, org.eclipse.equinox.p2.query, org.eclipse.equinox.p2.repository, diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java index b7265d817..ef82be0ef 100644 --- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java +++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java @@ -20,12 +20,15 @@ import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; import org.eclipse.equinox.internal.p2.metadata.IUMap; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.metadata.index.CapabilityIndex; +import org.eclipse.equinox.internal.p2.metadata.index.IdIndex; import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus; import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; +import org.eclipse.equinox.p2.metadata.index.*; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.repository.IRepository; @@ -38,7 +41,7 @@ import org.eclipse.equinox.p2.repository.spi.RepositoryReference; * location is a directory, this implementation will traverse the directory structure * and combine any metadata repository files that are found. */ -public class LocalMetadataRepository extends AbstractMetadataRepository { +public class LocalMetadataRepository extends AbstractMetadataRepository implements IIndexProvider<IInstallableUnit> { static final private String CONTENT_FILENAME = "content"; //$NON-NLS-1$ static final private String REPOSITORY_TYPE = LocalMetadataRepository.class.getName(); @@ -48,6 +51,8 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { protected IUMap units = new IUMap(); protected HashSet<RepositoryReference> repositories = new HashSet<RepositoryReference>(); + private IIndex<IInstallableUnit> idIndex; + private IIndex<IInstallableUnit> capabilityIndex; private static File getActualLocation(URI location, String extension) { File spec = URIUtil.toFile(location); @@ -92,6 +97,7 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { if (installableUnits == null || installableUnits.length == 0) return; units.addAll(installableUnits); + capabilityIndex = null; // Generated, not backed by units save(); } @@ -100,6 +106,21 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { repositories.add(new RepositoryReference(repositoryLocation, nickname, repositoryType, options)); } + public synchronized IIndex<IInstallableUnit> getIndex(String memberName) { + if (InstallableUnit.MEMBER_ID.equals(memberName)) { + if (idIndex == null) + idIndex = new IdIndex(units); + return idIndex; + } + + if (InstallableUnit.MEMBER_PROVIDED_CAPABILITIES.equals(memberName)) { + if (capabilityIndex == null) + capabilityIndex = new CapabilityIndex(units.iterator()); + return capabilityIndex; + } + return null; + } + public void initialize(RepositoryState state) { synchronized (this) { this.name = state.Name; @@ -146,13 +167,16 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { } public synchronized IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) { - if (query instanceof InstallableUnitQuery) - return units.query((InstallableUnitQuery) query); - return query.perform(units.iterator()); + return query instanceof IQueryWithIndex<?> ? ((IQueryWithIndex<IInstallableUnit>) query).perform(this) : query.perform(units.iterator()); + } + + public Iterator<IInstallableUnit> everything() { + return units.iterator(); } public synchronized void removeAll() { units.clear(); + capabilityIndex = null; // Generated, not backed by units. save(); } @@ -161,6 +185,7 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { if (installableUnits != null && installableUnits.length > 0) { changed = true; units.removeAll(Arrays.asList(installableUnits)); + capabilityIndex = null; // Generated, not backed by units. } if (changed) save(); @@ -219,4 +244,5 @@ public class LocalMetadataRepository extends AbstractMetadataRepository { manager.addRepository(this); return oldValue; } + } diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java index 63d548798..0ba7cd271 100644 --- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java +++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java @@ -12,13 +12,17 @@ package org.eclipse.equinox.internal.p2.metadata.repository; import java.net.URI; +import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.URIUtil; import org.eclipse.equinox.internal.p2.metadata.IUMap; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.metadata.index.CapabilityIndex; +import org.eclipse.equinox.internal.p2.metadata.index.IdIndex; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; +import org.eclipse.equinox.p2.metadata.index.*; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.repository.metadata.spi.AbstractMetadataRepository; @@ -26,7 +30,7 @@ import org.eclipse.equinox.p2.repository.metadata.spi.AbstractMetadataRepository /** * A metadata repository backed by an arbitrary URL. */ -public class URLMetadataRepository extends AbstractMetadataRepository { +public class URLMetadataRepository extends AbstractMetadataRepository implements IIndexProvider<IInstallableUnit> { public static final String CONTENT_FILENAME = "content"; //$NON-NLS-1$ public static final String XML_EXTENSION = ".xml"; //$NON-NLS-1$ @@ -35,6 +39,8 @@ public class URLMetadataRepository extends AbstractMetadataRepository { transient protected URI content; protected IUMap units = new IUMap(); + private IIndex<IInstallableUnit> idIndex; + private IIndex<IInstallableUnit> capabilityIndex; public static URI getActualLocation(URI base) { return getActualLocation(base, XML_EXTENSION); @@ -82,8 +88,25 @@ public class URLMetadataRepository extends AbstractMetadataRepository { } public synchronized IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) { - if (query instanceof InstallableUnitQuery) - return units.query((InstallableUnitQuery) query); - return query.perform(units.iterator()); + return (query instanceof IQueryWithIndex<?>) ? ((IQueryWithIndex<IInstallableUnit>) query).perform(this) : query.perform(units.iterator()); + } + + public synchronized IIndex<IInstallableUnit> getIndex(String memberName) { + if (InstallableUnit.MEMBER_ID.equals(memberName)) { + if (idIndex == null) + idIndex = new IdIndex(units); + return idIndex; + } + + if (InstallableUnit.MEMBER_PROVIDED_CAPABILITIES.equals(memberName)) { + if (capabilityIndex == null) + capabilityIndex = new CapabilityIndex(units.iterator()); + return capabilityIndex; + } + return null; + } + + public Iterator<IInstallableUnit> everything() { + return units.iterator(); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/.project b/bundles/org.eclipse.equinox.p2.metadata/.project index f697ae2d8..e81f675e0 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/.project +++ b/bundles/org.eclipse.equinox.p2.metadata/.project @@ -25,6 +25,11 @@ <arguments> </arguments> </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ds.core.builder</name> + <arguments> + </arguments> + </buildCommand> </buildSpec> <natures> <nature>org.eclipse.pde.PluginNature</nature> diff --git a/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF index ebd6d1ea3..bf5b7462c 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF @@ -18,8 +18,9 @@ Export-Package: org.eclipse.equinox.internal.p2.metadata; org.eclipse.equinox.p2.director, org.eclipse.equinox.p2.director.app, org.eclipse.equinox.p2.installer", - org.eclipse.equinox.internal.p2.metadata.expression;x-friends:="org.eclipse.equinox.p2.ql", + org.eclipse.equinox.internal.p2.metadata.expression;x-friends:="org.eclipse.equinox.p2.ql,org.eclipse.equinox.p2.artifact.repository,org.eclipse.equinox.p2.directorywatcher", org.eclipse.equinox.internal.p2.metadata.expression.parser;x-friends:="org.eclipse.equinox.p2.ql", + org.eclipse.equinox.internal.p2.metadata.index;x-friends:="org.eclipse.equinox.p2.director,org.eclipse.equinox.p2.metadata.repository,org.eclipse.equinox.p2.artifact.repository", org.eclipse.equinox.internal.p2.metadata.query; x-friends:="org.eclipse.equinox.p2.artifact.optimizers, org.eclipse.equinox.p2.artifact.processors, @@ -89,6 +90,7 @@ Export-Package: org.eclipse.equinox.internal.p2.metadata; org.eclipse.pde.core", org.eclipse.equinox.p2.metadata, org.eclipse.equinox.p2.metadata.expression, + org.eclipse.equinox.p2.metadata.index, org.eclipse.equinox.p2.metadata.query, org.eclipse.equinox.p2.query Import-Package: org.eclipse.osgi.service.localization;version="1.0.0", @@ -102,3 +104,4 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.5, Require-Bundle: org.eclipse.equinox.common, org.eclipse.equinox.p2.core, org.eclipse.osgi;bundle-version="3.5.0" +Service-Component: OSGI-INF/expressionFactory.xml, OSGI-INF/expressionParser.xml diff --git a/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionFactory.xml b/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionFactory.xml new file mode 100644 index 000000000..f7fede212 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionFactory.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.equinox.p2.metadata.expression.factory"> + <implementation class="org.eclipse.equinox.internal.p2.metadata.expression.ExpressionFactory"/> + <service> + <provide interface="org.eclipse.equinox.p2.metadata.expression.IExpressionFactory"/> + </service> + <property name="service.priority" type="Integer" value="1"/> +</scr:component> diff --git a/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionParser.xml b/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionParser.xml new file mode 100644 index 000000000..7a158de22 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/OSGI-INF/expressionParser.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.equinox.p2.metadata.expression.parser"> + <implementation class="org.eclipse.equinox.internal.p2.metadata.expression.parser.ExpressionParser"/> + <service> + <provide interface="org.eclipse.equinox.p2.metadata.expression.IExpressionParser"/> + </service> +</scr:component>
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.metadata/build.properties b/bundles/org.eclipse.equinox.p2.metadata/build.properties index 246ea6cb7..0feab6a85 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/build.properties +++ b/bundles/org.eclipse.equinox.p2.metadata/build.properties @@ -13,7 +13,9 @@ output.. = bin/ bin.includes = META-INF/,\ .,\ about.html,\ - plugin.properties -src.includes = about.html + plugin.properties,\ + OSGI-INF/ +src.includes = about.html,\ + OSGI-INF/ javacTarget=jsr14 javacSource=1.5 diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ArtifactKey.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ArtifactKey.java index 709fa2b1c..bdd70f866 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ArtifactKey.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ArtifactKey.java @@ -10,21 +10,25 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.metadata; -import org.eclipse.equinox.p2.metadata.Version; - import java.util.ArrayList; import java.util.StringTokenizer; import org.eclipse.core.runtime.Assert; import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.expression.IMemberProvider; /** * The concrete type for representing IArtifactKey's. * <p> * See {link IArtifact for a description of the lifecycle of artifact keys) */ -public class ArtifactKey implements IArtifactKey { +public class ArtifactKey implements IArtifactKey, IMemberProvider { private static final String SEPARATOR = ","; //$NON-NLS-1$ + public static final String MEMBER_ID = "id"; //$NON-NLS-1$ + public static final String MEMBER_CLASSIFIER = "classifier"; //$NON-NLS-1$ + public static final String MEMBER_VERSION = "version"; //$NON-NLS-1$ + private final String id; private final String classifier; private final Version version; @@ -123,4 +127,17 @@ public class ArtifactKey implements IArtifactKey { return data.toString(); } + public Object getMember(String memberName) { + // It is OK to use identity comparisons here since + // a) All constant valued strings are always interned + // b) The Member constructor always interns the name + // + if (MEMBER_ID == memberName) + return id; + if (MEMBER_VERSION == memberName) + return version; + if (MEMBER_CLASSIFIER == memberName) + return classifier; + throw new IllegalArgumentException(); + } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/IUMap.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/IUMap.java index 3ce2054da..32715828f 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/IUMap.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/IUMap.java @@ -16,7 +16,6 @@ import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; -import org.eclipse.equinox.p2.query.Collector; import org.eclipse.equinox.p2.query.IQueryResult; /** @@ -142,16 +141,8 @@ public class IUMap { Iterator<IInstallableUnit> candidates; if (query.getId() == null) candidates = iterator(); - else { - Object bucket = units.get(query.getId()); - if (bucket == null) - return Collector.emptyCollector(); - - if (bucket.getClass().isArray()) - candidates = CollectionUtils.unmodifiableList((IInstallableUnit[]) bucket).iterator(); - else - candidates = Collections.<IInstallableUnit> singletonList((IInstallableUnit) bucket).iterator(); - } + else + candidates = getUnits(query.getId()).iterator(); return query.perform(candidates); } @@ -160,6 +151,18 @@ public class IUMap { return get(unit.getId(), unit.getVersion()) != null; } + /** + * Returns a collection of units that has the given <code>id</code>. + * @param id The id of the desired units. Must not be <code>null</code>. + * @return The units corresponding to the given <code>id</code>. + */ + public Collection<IInstallableUnit> getUnits(String id) { + Object bucket = units.get(id); + if (bucket == null) + return CollectionUtils.emptyList(); + return bucket.getClass().isArray() ? CollectionUtils.unmodifiableList((IInstallableUnit[]) bucket) : Collections.<IInstallableUnit> singletonList((IInstallableUnit) bucket); + } + public IQueryResult<IInstallableUnit> get(String id) { return internalGet(id, null); } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Messages.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Messages.java index 0466d2676..654d4c0aa 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Messages.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Messages.java @@ -131,6 +131,10 @@ public class Messages extends NLS { public static String unbalanced_format_parenthesis; + public static String no_expression_factory; + + public static String no_expression_parser; + private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.p2.metadata.messages"; //$NON-NLS-1$ static { diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/MetadataActivator.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/MetadataActivator.java index 40881fcc0..686d11de8 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/MetadataActivator.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/MetadataActivator.java @@ -10,23 +10,109 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.metadata; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.p2.metadata.expression.IExpressionFactory; +import org.eclipse.equinox.p2.metadata.expression.IExpressionParser; +import org.osgi.framework.*; public class MetadataActivator implements BundleActivator { public static final String PI_METADATA = "org.eclipse.equinox.p2.metadata"; //$NON-NLS-1$ - public static BundleContext context; + + public static final String SERVICE_PRIORITY = "service.priority"; //$NON-NLS-1$ + + public static MetadataActivator instance; + + private BundleContext context; + private IExpressionFactory expressionFactory; + private ServiceReference expressionFactoryReference; + private IExpressionParser expressionParser; + private ServiceReference expressionParserReference; public static BundleContext getContext() { - return context; + MetadataActivator activator = instance; + return activator == null ? null : activator.context; + } + + public static IExpressionFactory getExpressionFactory() { + MetadataActivator activator = instance; + return activator == null ? null : activator._getExpressionFactory(); + } + + public static IExpressionParser getExpressionParser() { + MetadataActivator activator = instance; + return activator == null ? null : activator._getExpressionParser(); } public void start(BundleContext aContext) throws Exception { - MetadataActivator.context = aContext; + context = aContext; + instance = this; } public void stop(BundleContext aContext) throws Exception { - MetadataActivator.context = null; + instance = null; + + if (expressionFactoryReference != null) { + aContext.ungetService(expressionFactoryReference); + expressionFactoryReference = null; + expressionFactory = null; + } + if (expressionParserReference != null) { + aContext.ungetService(expressionParserReference); + expressionParserReference = null; + expressionParser = null; + } } + private ServiceReference getBestReference(Class<?> serviceInterface) { + ServiceReference[] refs; + String serviceName = serviceInterface.getName(); + try { + refs = context.getAllServiceReferences(serviceName, null); + } catch (InvalidSyntaxException e) { + LogHelper.log(new Status(IStatus.ERROR, context.getBundle().getSymbolicName(), "Unable to obtain service references for service " + serviceName, e)); //$NON-NLS-1$ + return null; + } + + if (refs == null) + return null; + + ServiceReference best = null; + int idx = refs.length; + while (--idx >= 0) { + ServiceReference ref = refs[idx]; + if (best == null) { + best = ref; + continue; + } + Integer refPrio = (Integer) ref.getProperty(SERVICE_PRIORITY); + Integer bestPrio = (Integer) best.getProperty(SERVICE_PRIORITY); + if (refPrio == null) + continue; + if (bestPrio == null || bestPrio.intValue() < refPrio.intValue()) + best = ref; + } + return best; + } + + private synchronized IExpressionFactory _getExpressionFactory() { + if (expressionFactory == null) { + expressionFactoryReference = getBestReference(IExpressionFactory.class); + if (expressionFactoryReference == null) + throw new IllegalStateException(Messages.no_expression_factory); + expressionFactory = (IExpressionFactory) context.getService(expressionFactoryReference); + } + return expressionFactory; + } + + private synchronized IExpressionParser _getExpressionParser() { + if (expressionParser == null) { + expressionParserReference = getBestReference(IExpressionParser.class); + if (expressionParserReference == null) + throw new IllegalStateException(Messages.no_expression_parser); + expressionParser = (IExpressionParser) context.getService(expressionParserReference); + } + return expressionParser; + } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java index 4fcb387fc..7a43439c8 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java @@ -256,13 +256,21 @@ public class RequiredCapability implements IRequiredCapability, IMemberProvider return new VersionRange(v, expr == range_II_Expression || expr == range_IN_Expression, h, expr == range_II_Expression || expr == range_NI_Expression); } + public static boolean isSimpleRequirement(IMatchExpression<IInstallableUnit> matchExpression) { + return isPredefined(ExpressionUtil.getOperand(matchExpression)); + } + private static IExpression assertValid(IMatchExpression<IInstallableUnit> matchExpression) { IExpression expr = ExpressionUtil.getOperand(matchExpression); - if (!(expr == allVersionsExpression || expr == range_II_Expression || expr == range_IN_Expression || expr == range_NI_Expression || expr == range_NN_Expression || expr == strictVersionExpression || expr == openEndedExpression || expr == openEndedNonInclusiveExpression)) + if (!isPredefined(expr)) throw new IllegalArgumentException(); return expr; } + private static boolean isPredefined(IExpression expr) { + return expr == allVersionsExpression || expr == range_II_Expression || expr == range_IN_Expression || expr == range_NI_Expression || expr == range_NN_Expression || expr == strictVersionExpression || expr == openEndedExpression || expr == openEndedNonInclusiveExpression; + } + public Object getMember(String memberName) { // It is OK to use identity comparisons here since // a) All constant valued strings are always interned diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/TranslationSupport.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/TranslationSupport.java index e42289040..9f11ef4e3 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/TranslationSupport.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/TranslationSupport.java @@ -193,7 +193,7 @@ public class TranslationSupport { SoftReference<IQueryResult<IInstallableUnit>> queryResultReference = localeCollectorCache.get(locale); if (queryResultReference != null) { - Collector<IInstallableUnit> cached = (Collector<IInstallableUnit>) queryResultReference.get(); + IQueryResult<IInstallableUnit> cached = queryResultReference.get(); if (cached != null) return cached; } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java index c69e75e32..6a017aea3 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java @@ -64,7 +64,7 @@ public abstract class CoercingComparator<T> { return (Class<?>) v; if (v instanceof String) { try { - return MetadataActivator.context.getBundle().loadClass(((String) v).trim()); + return MetadataActivator.getContext().getBundle().loadClass(((String) v).trim()); } catch (Exception e) { // } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CollectionFilter.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CollectionFilter.java index bb845d373..f4d320149 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CollectionFilter.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CollectionFilter.java @@ -13,6 +13,8 @@ package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.Iterator; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; import org.eclipse.equinox.p2.metadata.expression.IExpressionVisitor; +import org.eclipse.equinox.p2.metadata.index.IIndex; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; /** * Some kind of operation that is performed for each element of a collection. I.e. @@ -51,13 +53,13 @@ public abstract class CollectionFilter extends Unary { } public final Object evaluate(IEvaluationContext context) { - Iterator<?> lval = operand.evaluateAsIterator(context); + Iterator<?> lval = getInnerIterator(context); context = lambda.prolog(context); return evaluate(context, lval); } public final Iterator<?> evaluateAsIterator(IEvaluationContext context) { - Iterator<?> lval = operand.evaluateAsIterator(context); + Iterator<?> lval = getInnerIterator(context); context = lambda.prolog(context); return evaluateAsIterator(context, lval); } @@ -82,4 +84,47 @@ public abstract class CollectionFilter extends Unary { protected Iterator<?> evaluateAsIterator(IEvaluationContext context, Iterator<?> iterator) { throw new UnsupportedOperationException(); } + + private transient IIndexProvider<?> lastIndexProvider; + private transient IIndex<?> lastIndex; + + private IIndex<?> getIndex(Class<?> elementClass, IIndexProvider<?> indexProvider) { + if (lastIndexProvider == indexProvider) + return lastIndex; + + for (String member : getIndexCandidateMembers(elementClass, lambda.getItemVariable(), lambda.getOperand())) { + IIndex<?> index = indexProvider.getIndex(member); + if (index != null) + lastIndex = index; + } + lastIndexProvider = indexProvider; + return lastIndex; + } + + protected Iterator<?> getInnerIterator(IEvaluationContext context) { + Object collection = operand.evaluate(context); + if (collection instanceof Everything<?>) { + // Try to find an index + // + IIndexProvider<?> indexProvider = context.getIndexProvider(); + if (indexProvider != null) { + Class<?> elementClass = ((Everything<?>) collection).getElementClass(); + IIndex<?> index = getIndex(elementClass, indexProvider); + if (index != null) { + Iterator<?> indexed = index.getCandidates(context, lambda.getItemVariable(), lambda.getOperand()); + if (indexed != null) + return indexed; + } + } + } + + // No index. We need every element + if (collection instanceof IRepeatableIterator<?>) + return ((IRepeatableIterator<?>) collection).getCopy(); + + Iterator<?> itor = RepeatableIterator.create(collection); + if (operand instanceof Variable) + ((Variable) operand).setValue(context, itor); + return itor; + } } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CompoundIterator.java index 179a36613..4aaf2a417 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CompoundIterator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Cloudsmith Inc. and others. + * Copyright (c) 2009 - 2010 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 @@ -8,26 +8,34 @@ * Contributors: * Cloudsmith Inc. - initial API and implementation *******************************************************************************/ -package org.eclipse.equinox.internal.p2.ql; - -import org.eclipse.equinox.internal.p2.metadata.expression.RepeatableIterator; +package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.Iterator; import java.util.NoSuchElementException; /** - * A FlattenIterator will assume that its operand is an iterator that will produce - * elements that can be represented as iterators. The elements of those iterators - * will be returned in sequence, thus removing one iterator dimension. + * A CompoundIterator will assume that its contained iterator that will produce + * elements that in turn can be represented as iterators. The elements of those + * iterators will be returned in sequence, thus removing one iterator dimension. + * Elements of the contained iterator that are not iterators will be coerced + * into iterators using {@link RepeatableIterator#create(Object)}. */ -public class FlattenIterator<T> implements Iterator<T> { +public class CompoundIterator<T> implements Iterator<T> { private static final Object NO_ELEMENT = new Object(); private final Iterator<? extends Object> iteratorIterator; private Iterator<T> currentIterator; private T nextObject = noElement(); - public FlattenIterator(Iterator<? extends Object> iterator) { + /** + * Creates a compound iterator that will iterated over the elements + * of the provided <code>iterator</code>. Each element will be coerced + * into an iterator and its elements in turn are returned + * in succession by the compound iterator. + * + * @param iterator + */ + public CompoundIterator(Iterator<? extends Object> iterator) { this.iteratorIterator = iterator; } @@ -44,6 +52,11 @@ public class FlattenIterator<T> implements Iterator<T> { return nxt; } + /** + * Remove is not supported by this iterator so calling this method + * will always yield an exception. + * @throws UnsupportedOperationException + */ public void remove() { throw new UnsupportedOperationException(); } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ContextExpression.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ContextExpression.java new file mode 100644 index 000000000..ec2394f50 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ContextExpression.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2009 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.metadata.expression; + +import java.util.Iterator; +import org.eclipse.equinox.p2.metadata.expression.*; + +/** + * The context expression is the top expression in context queries. It introduces the + * variable 'everything' and initialized it with the iterator that represents all + * available items. + */ +public class ContextExpression<T> extends Unary implements IContextExpression<T> { + private static final Object[] noParams = new Object[0]; + protected final Object[] parameters; + + public ContextExpression(Expression expression, Object[] parameters) { + super(expression); + this.parameters = parameters == null ? noParams : parameters; + } + + public boolean accept(IExpressionVisitor visitor) { + return visitor.visit(operand); + } + + public void toString(StringBuffer bld, Variable rootVariable) { + operand.toString(bld, rootVariable); + } + + public IEvaluationContext createContext(Class<T> elementClass, Iterator<T> iterator) { + Variable everything = ExpressionFactory.EVERYTHING; + IEvaluationContext context = EvaluationContext.create(parameters, everything); + context.setValue(everything, new Everything<T>(elementClass, iterator, operand)); + return context; + } + + public int getExpressionType() { + return 0; + } + + public String getOperator() { + throw new UnsupportedOperationException(); + } + + public int getPriority() { + return operand.getPriority(); + } + + public Object[] getParameters() { + return parameters; + } + + public int hashCode() { + return operand.hashCode(); + } + + @SuppressWarnings("unchecked") + public Iterator<T> iterator(IEvaluationContext context) { + return (Iterator<T>) evaluateAsIterator(context); + } + + public void toString(StringBuffer bld) { + toString(bld, ExpressionFactory.EVERYTHING); + } +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/EvaluationContext.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/EvaluationContext.java index 6048a008a..49e9bbcac 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/EvaluationContext.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/EvaluationContext.java @@ -12,17 +12,18 @@ package org.eclipse.equinox.internal.p2.metadata.expression; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; import org.eclipse.equinox.p2.metadata.expression.IExpression; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; /** * Highly specialized evaluation contexts optimized for misc purposes */ public class EvaluationContext implements IEvaluationContext { - static class SingleVariableContext extends EvaluationContext { + public static class SingleVariableContext extends EvaluationContext { private Object value; private final IExpression variable; - public SingleVariableContext(IEvaluationContext parentContext, IExpression variable, Object[] parameters) { + public SingleVariableContext(EvaluationContext parentContext, IExpression variable, Object[] parameters) { super(parentContext, parameters); this.variable = variable; } @@ -39,10 +40,10 @@ public class EvaluationContext implements IEvaluationContext { } } - static class MultiVariableContext extends EvaluationContext { + public static class MultiVariableContext extends EvaluationContext { private final Object[] values; - public MultiVariableContext(IEvaluationContext parentContext, IExpression[] variables, Object[] parameters) { + public MultiVariableContext(EvaluationContext parentContext, IExpression[] variables, Object[] parameters) { super(parentContext, parameters); values = new Object[variables.length * 2]; for (int idx = 0, ndx = 0; ndx < variables.length; ++ndx, idx += 2) @@ -75,7 +76,7 @@ public class EvaluationContext implements IEvaluationContext { } public static IEvaluationContext create(IEvaluationContext parent, IExpression variable) { - return new SingleVariableContext(parent, variable, ((EvaluationContext) parent).parameters); + return new SingleVariableContext((EvaluationContext) parent, variable, ((EvaluationContext) parent).parameters); } public static IEvaluationContext create(IEvaluationContext parent, IExpression[] variables) { @@ -87,13 +88,13 @@ public class EvaluationContext implements IEvaluationContext { return create(parent, parameters); if (parameters == null) parameters = noParameters; - return variables.length == 1 ? new SingleVariableContext(parent, variables[0], parameters) : new MultiVariableContext(parent, variables, parameters); + return variables.length == 1 ? new SingleVariableContext((EvaluationContext) parent, variables[0], parameters) : new MultiVariableContext((EvaluationContext) parent, variables, parameters); } public static IEvaluationContext create(IEvaluationContext parent, Object[] parameters) { if (parameters == null) parameters = noParameters; - return new EvaluationContext(parent, parameters); + return new EvaluationContext((EvaluationContext) parent, parameters); } public static IEvaluationContext create(IExpression variable) { @@ -114,11 +115,13 @@ public class EvaluationContext implements IEvaluationContext { return create(INSTANCE, parameters, variables); } - final IEvaluationContext parentContext; + final EvaluationContext parentContext; private final Object[] parameters; - EvaluationContext(IEvaluationContext parentContext, Object[] parameters) { + private IIndexProvider<?> indexProvider; + + EvaluationContext(EvaluationContext parentContext, Object[] parameters) { this.parentContext = parentContext; this.parameters = parameters; } @@ -138,4 +141,17 @@ public class EvaluationContext implements IEvaluationContext { throw new IllegalArgumentException("No such variable: " + variable); //$NON-NLS-1$ parentContext.setValue(variable, value); } + + public IIndexProvider<?> getIndexProvider() { + if (indexProvider == null) { + if (parentContext == null) + return null; + return parentContext.getIndexProvider(); + } + return indexProvider; + } + + public void setIndexProvider(IIndexProvider<?> indexProvider) { + this.indexProvider = indexProvider; + } } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Everything.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Everything.java index d127bf72a..ebdb720b8 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Everything.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Everything.java @@ -8,15 +8,14 @@ * Contributors: * Cloudsmith Inc. - initial API and implementation *******************************************************************************/ -package org.eclipse.equinox.internal.p2.ql; - -import org.eclipse.equinox.internal.p2.metadata.expression.IRepeatableIterator; - -import org.eclipse.equinox.internal.p2.metadata.expression.RepeatableIterator; +package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.Collection; import java.util.Iterator; import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; +import org.eclipse.equinox.p2.metadata.expression.IExpression; +import org.eclipse.equinox.p2.metadata.expression.IExpressionVisitor; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; /** * The immutable context used when evaluating an expression. @@ -31,7 +30,16 @@ public final class Everything<T> extends MatchIteratorFilter<T> implements IRepe this.elementClass = elementClass; } - public Everything(Class<T> elementClass, Iterator<? extends T> iterator, boolean needsRepeat) { + public Everything(Class<T> elementClass, Iterator<? extends T> iterator, Expression expression) { + this(elementClass, iterator, needsRepeadedAccessToEverything(expression)); + } + + public Everything(Class<T> elementClass, IIndexProvider<? extends T> indexProvider) { + super(RepeatableIterator.<T> create(indexProvider)); + this.elementClass = elementClass; + } + + Everything(Class<T> elementClass, Iterator<? extends T> iterator, boolean needsRepeat) { super(needsRepeat ? RepeatableIterator.create(iterator) : iterator); this.elementClass = elementClass; } @@ -50,6 +58,10 @@ public final class Everything<T> extends MatchIteratorFilter<T> implements IRepe return super.next(); } + public Class<T> getElementClass() { + return elementClass; + } + public Object getIteratorProvider() { Iterator<? extends T> iterator = getInnerIterator(); if (iterator instanceof IRepeatableIterator<?>) @@ -60,4 +72,24 @@ public final class Everything<T> extends MatchIteratorFilter<T> implements IRepe protected boolean isMatch(T val) { return elementClass.isInstance(val); } + + /** + * Checks if the expression will make repeated requests for the 'everything' iterator. + * @return <code>true</code> if repeated requests will be made, <code>false</code> if not. + */ + private static boolean needsRepeadedAccessToEverything(Expression expression) { + final boolean[] repeatedAccessNeeded = new boolean[] {false}; + expression.accept(new IExpressionVisitor() { + public boolean visit(IExpression expr) { + // FIXME Needs proper counting + if (expr == ExpressionFactory.EVERYTHING) { + repeatedAccessNeeded[0] = true; + return false; + } + return true; + } + }); + // return repeatedAccessNeeded[0]; + return true; + } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Expression.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Expression.java index 75f47dd94..767f7c1e7 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Expression.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Expression.java @@ -11,6 +11,8 @@ package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.*; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.expression.*; /** @@ -93,6 +95,12 @@ public abstract class Expression implements IExpression, Comparable<Expression>, } } + public static Collection<String> getIndexCandidateMembers(Class<?> elementClass, Variable itemVariable, Expression operand) { + MembersFinder finder = new MembersFinder(elementClass, itemVariable); + operand.accept(finder); + return finder.getMembers(); + } + /** * Let the visitor visit this instance and all expressions that this * instance contains. @@ -264,6 +272,45 @@ public abstract class Expression implements IExpression, Comparable<Expression>, } } + private static class MembersFinder implements IExpressionVisitor { + private final ArrayList<String> members = new ArrayList<String>(); + private final Class<?> elementClass; + private final IExpression operand; + + MembersFinder(Class<?> elementClass, IExpression operand) { + this.elementClass = elementClass; + this.operand = operand; + } + + public boolean visit(IExpression expression) { + if (expression instanceof Member) { + Member member = (Member) expression; + if (member.getOperand() == operand) { + String name = member.getName(); + if (!members.contains(name)) + members.add(member.getName()); + return false; + } + } else if (expression instanceof Matches && IInstallableUnit.class.isAssignableFrom(elementClass)) { + // This one is a bit special since an + // IInstallableUnit ~= IRequirement often + // means that we can reuse the requirement + // expression. + Matches matches = (Matches) expression; + if (matches.lhs == operand) { + if (!members.contains(InstallableUnit.MEMBER_PROVIDED_CAPABILITIES)) + members.add(InstallableUnit.MEMBER_PROVIDED_CAPABILITIES); + return false; + } + } + return true; + } + + Collection<String> getMembers() { + return members; + } + } + static Expression addFilter(Expression base, Expression subFilter, int expressionType) { if (base.equals(subFilter)) return base; diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ExpressionFactory.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ExpressionFactory.java index f87c1c129..fc0ab18d5 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ExpressionFactory.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/ExpressionFactory.java @@ -6,6 +6,7 @@ import org.eclipse.equinox.p2.metadata.expression.*; public class ExpressionFactory implements IExpressionFactory, IExpressionConstants { public static final IExpressionFactory INSTANCE = new ExpressionFactory(); public static final Variable THIS = new Variable(VARIABLE_THIS); + public static final Variable EVERYTHING = new Variable(VARIABLE_EVERYTHING); protected static Expression[] convertArray(IExpression[] operands) { Expression[] ops = new Expression[operands.length]; @@ -13,10 +14,6 @@ public class ExpressionFactory implements IExpressionFactory, IExpressionConstan return ops; } - protected ExpressionFactory() { - // Maintain singleton - } - public IExpression all(IExpression collection, IExpression lambda) { return new All((Expression) collection, (LambdaExpression) lambda); } @@ -50,6 +47,10 @@ public class ExpressionFactory implements IExpressionFactory, IExpressionConstan return EvaluationContext.create(parameters, variables); } + public <T> IContextExpression<T> contextExpression(IExpression expr, Object... parameters) { + return new ContextExpression<T>((Expression) expr, parameters); + } + public IFilterExpression filterExpression(IExpression expression) { return new LDAPFilter((Expression) expression); } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/MatchIteratorFilter.java index 1f7b00d2a..8d21ed8f7 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/MatchIteratorFilter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Cloudsmith Inc. and others. + * Copyright (c) 2009 - 2010 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 @@ -8,7 +8,7 @@ * Contributors: * Cloudsmith Inc. - initial API and implementation *******************************************************************************/ -package org.eclipse.equinox.internal.p2.ql; +package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/RepeatableIterator.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/RepeatableIterator.java index e44a4e507..b7325286c 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/RepeatableIterator.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/RepeatableIterator.java @@ -11,6 +11,7 @@ package org.eclipse.equinox.internal.p2.metadata.expression; import java.util.*; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; import org.eclipse.equinox.p2.query.IQueryResult; public class RepeatableIterator<T> implements IRepeatableIterator<T> { @@ -121,14 +122,33 @@ public class RepeatableIterator<T> implements IRepeatableIterator<T> { } } - static class CollectionIterator<T> implements IRepeatableIterator<T> { - private final Collection<T> collection; + static abstract class DeferredIterator<T> implements IRepeatableIterator<T> { + private Iterator<T> iterator; - private final Iterator<T> iterator; + public boolean hasNext() { + if (iterator == null) + iterator = getIterator(); + return iterator.hasNext(); + } + + public T next() { + if (iterator == null) + iterator = getIterator(); + return iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + abstract Iterator<T> getIterator(); + } + + static class CollectionIterator<T> extends DeferredIterator<T> { + private final Collection<T> collection; CollectionIterator(Collection<T> collection) { this.collection = collection; - this.iterator = collection.iterator(); } public IRepeatableIterator<T> getCopy() { @@ -139,16 +159,28 @@ public class RepeatableIterator<T> implements IRepeatableIterator<T> { return collection; } - public boolean hasNext() { - return iterator.hasNext(); + Iterator<T> getIterator() { + return collection.iterator(); } + } - public T next() { - return iterator.next(); + static class IndexProviderIterator<T> extends DeferredIterator<T> { + private final IIndexProvider<T> indexProvider; + + IndexProviderIterator(IIndexProvider<T> indexProvider) { + this.indexProvider = indexProvider; } - public void remove() { - throw new UnsupportedOperationException(); + public IRepeatableIterator<T> getCopy() { + return new IndexProviderIterator<T>(indexProvider); + } + + public Object getIteratorProvider() { + return indexProvider; + } + + Iterator<T> getIterator() { + return indexProvider.everything(); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/parser/ExpressionParser.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/parser/ExpressionParser.java index 905d0927c..322299ffc 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/parser/ExpressionParser.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/parser/ExpressionParser.java @@ -10,10 +10,10 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.metadata.expression.parser; -import org.eclipse.equinox.internal.p2.metadata.expression.LDAPApproximation; - import java.util.*; +import org.eclipse.equinox.internal.p2.metadata.MetadataActivator; import org.eclipse.equinox.internal.p2.metadata.expression.IExpressionConstants; +import org.eclipse.equinox.internal.p2.metadata.expression.LDAPApproximation; import org.eclipse.equinox.p2.metadata.expression.*; public class ExpressionParser extends Stack<IExpression> implements IExpressionConstants, IExpressionParser { @@ -77,8 +77,8 @@ public class ExpressionParser extends Stack<IExpression> implements IExpressionC protected Object tokenValue; protected String rootVariable; - public ExpressionParser(IExpressionFactory factory) { - this.factory = factory; + public ExpressionParser() { + factory = MetadataActivator.getExpressionFactory(); } public synchronized IExpression parse(String exprString) { @@ -100,6 +100,24 @@ public class ExpressionParser extends Stack<IExpression> implements IExpressionC } } + public synchronized IExpression parseQuery(String exprString) { + expression = exprString; + tokenPos = 0; + currentToken = 0; + tokenValue = null; + rootVariable = VARIABLE_EVERYTHING; + IExpression everythingVariable = factory.variable(VARIABLE_EVERYTHING); + push(everythingVariable); + try { + nextToken(); + IExpression expr = parseCondition(); + assertToken(TOKEN_END); + return expr; + } finally { + popVariable(); // pop context + } + } + protected Map<String, Integer> keywordToTokenMap() { return keywords; } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java new file mode 100644 index 000000000..a26fd3034 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.metadata.index; + +import java.util.*; +import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; +import org.eclipse.equinox.internal.p2.metadata.*; +import org.eclipse.equinox.internal.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.expression.*; + +/** + * An in-memory implementation of a CapabilityIndex based on a Map. + */ +@SuppressWarnings("unchecked") +public class CapabilityIndex extends Index<IInstallableUnit> { + + private final Map<String, Object> capabilityMap; + + public CapabilityIndex(Iterator<IInstallableUnit> itor) { + HashMap<String, Object> index = new HashMap<String, Object>(300); + while (itor.hasNext()) { + IInstallableUnit iu = itor.next(); + Collection<IProvidedCapability> pcs = iu.getProvidedCapabilities(); + for (IProvidedCapability pc : pcs) { + String name = pc.getName(); + Object prev = index.put(name, iu); + if (prev == null || prev == iu) + continue; + + ArrayList<IInstallableUnit> list; + if (prev instanceof IInstallableUnit) { + list = new ArrayList<IInstallableUnit>(); + list.add((IInstallableUnit) prev); + } else + list = (ArrayList<IInstallableUnit>) prev; + list.add(iu); + index.put(name, list); + } + } + this.capabilityMap = index; + } + + private Object getRequirementIDs(IEvaluationContext ctx, IExpression requirement, Object queriedKeys) { + switch (requirement.getExpressionType()) { + case IExpression.TYPE_AND : + // AND is OK if at least one of the branches require the queried key + for (IExpression expr : ExpressionUtil.getOperands(requirement)) { + Object test = getRequirementIDs(ctx, expr, queriedKeys); + if (test != null) { + if (test == Boolean.FALSE) + // Failing exists so the AND will fail altogether + return test; + + // It's safe to break here since an and'ing several queries + // for different keys and the same input will yield false anyway. + return test; + } + } + return null; + + case IExpression.TYPE_OR : + // OR is OK if all the branches require the queried key + for (IExpression expr : ExpressionUtil.getOperands(requirement)) { + Object test = getRequirementIDs(ctx, expr, queriedKeys); + if (test == null) + // This branch did not require the key so index cannot be used + return null; + + if (test == Boolean.FALSE) + // Branch will always fail regardless of input, so just ignore + continue; + + queriedKeys = test; + } + return queriedKeys; + + case IExpression.TYPE_ALL : + case IExpression.TYPE_EXISTS : + CollectionFilter cf = (CollectionFilter) requirement; + if (isIndexedMember(cf.getOperand(), ExpressionFactory.THIS, InstallableUnit.MEMBER_PROVIDED_CAPABILITIES)) { + LambdaExpression lambda = cf.lambda; + return getQueriedIDs(ctx, lambda.getItemVariable(), ProvidedCapability.MEMBER_NAME, lambda.getOperand(), queriedKeys); + } + } + return null; + } + + @Override + protected Object getQueriedIDs(IEvaluationContext ctx, IExpression variable, String memberName, IExpression booleanExpr, Object queriedKeys) { + if (booleanExpr.getExpressionType() != IExpression.TYPE_MATCHES) + return super.getQueriedIDs(ctx, variable, memberName, booleanExpr, queriedKeys); + + Matches matches = (Matches) booleanExpr; + if (matches.lhs != variable) + return null; + + Object rhsObj = matches.rhs.evaluate(ctx); + if (!(rhsObj instanceof IRequirement)) + return null; + + // Let the requirement expression participate in the + // index usage query + // + IMatchExpression<IInstallableUnit> rm = ((IRequirement) rhsObj).getMatches(); + return RequiredCapability.isSimpleRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys); + } + + public Iterator<IInstallableUnit> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr) { + Object queriedKeys = null; + + // booleanExpression must be a collection filter on providedCapabilities + // or an IInstallableUnit used in a match expression. + // + IExpression expr = booleanExpr; + int type = booleanExpr.getExpressionType(); + if (type == 0) { + // wrapper + expr = ((Unary) booleanExpr).operand; + type = expr.getExpressionType(); + } + + switch (type) { + case IExpression.TYPE_ALL : + case IExpression.TYPE_EXISTS : + CollectionFilter cf = (CollectionFilter) expr; + if (isIndexedMember(cf.getOperand(), variable, InstallableUnit.MEMBER_PROVIDED_CAPABILITIES)) { + // This is providedCapabilities.exists or providedCapabilites.all + // + LambdaExpression lambda = cf.lambda; + queriedKeys = getQueriedIDs(ctx, lambda.getItemVariable(), ProvidedCapability.MEMBER_NAME, lambda.getOperand(), queriedKeys); + } else { + // Might be the requiredCapabilities array. + // + Expression op = cf.getOperand(); + if (op instanceof Member && InstallableUnit.MEMBER_REQUIRED_CAPABILITIES.equals(((Member) op).getName())) { + queriedKeys = getQueriedIDs(ctx, variable, ProvidedCapability.MEMBER_NAME, booleanExpr, queriedKeys); + } + } + break; + + case IExpression.TYPE_MATCHES : + Matches matches = (Matches) expr; + if (matches.lhs != variable) + break; + + Object rhsObj = matches.rhs.evaluate(ctx); + if (!(rhsObj instanceof IRequirement)) + break; + + // Let the requirement expression participate in the + // index usage query + // + IMatchExpression<IInstallableUnit> rm = ((IRequirement) rhsObj).getMatches(); + queriedKeys = RequiredCapability.isSimpleRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys); + break; + + default : + queriedKeys = null; + } + + if (queriedKeys == null) + // Index cannot be used. + return null; + + Collection<IInstallableUnit> matchingIUs; + if (queriedKeys == Boolean.FALSE) { + // It has been determined that the expression has no chance + // to succeed regardless of input + matchingIUs = CollectionUtils.<IInstallableUnit> emptySet(); + } else if (queriedKeys instanceof Collection<?>) { + matchingIUs = new HashSet<IInstallableUnit>(); + for (Object key : (Collection<Object>) queriedKeys) + collectMatchingIUs((String) key, matchingIUs); + } else { + Object v = capabilityMap.get(queriedKeys); + if (v == null) + matchingIUs = CollectionUtils.<IInstallableUnit> emptySet(); + else if (v instanceof IInstallableUnit) + matchingIUs = Collections.singleton((IInstallableUnit) v); + else + matchingIUs = (Collection<IInstallableUnit>) v; + } + return matchingIUs.iterator(); + } + + private void collectMatchingIUs(String name, Collection<IInstallableUnit> collector) { + Object v = capabilityMap.get(name); + if (v == null) + return; + if (v instanceof IInstallableUnit) + collector.add((IInstallableUnit) v); + else + collector.addAll((Collection<IInstallableUnit>) v); + } +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/IdIndex.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/IdIndex.java new file mode 100644 index 000000000..a415e8ca4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/IdIndex.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.metadata.index; + +import java.util.*; +import org.eclipse.equinox.internal.p2.metadata.IUMap; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.expression.IExpression; + +public class IdIndex extends Index<IInstallableUnit> { + private final IUMap iuMap; + + public IdIndex(IUMap iuMap) { + this.iuMap = iuMap; + } + + public IdIndex(Iterator<IInstallableUnit> ius) { + iuMap = new IUMap(); + while (ius.hasNext()) + iuMap.add(ius.next()); + } + + public Iterator<IInstallableUnit> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr) { + Object queriedKeys = getQueriedIDs(ctx, variable, InstallableUnit.MEMBER_ID, booleanExpr, null); + if (queriedKeys == null) + return null; + + if (queriedKeys instanceof Collection<?>) { + HashSet<IInstallableUnit> collector = new HashSet<IInstallableUnit>(); + for (Object key : (Collection<?>) queriedKeys) + collector.addAll(iuMap.getUnits((String) key)); + return collector.iterator(); + } + return iuMap.getUnits((String) queriedKeys).iterator(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/Index.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/Index.java new file mode 100644 index 000000000..3c509bff2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/Index.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.metadata.index; + +import java.util.ArrayList; +import java.util.Iterator; +import org.eclipse.equinox.internal.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.index.IIndex; + +public abstract class Index<T> implements IIndex<T> { + + protected static boolean isIndexedMember(IExpression expr, IExpression variable, String memberName) { + if (expr instanceof Member) { + Member member = (Member) expr; + return member.getOperand() == variable && member.getName().equals(memberName); + } + return false; + } + + protected static Object concatenateUnique(Object previous, Object toAdd) { + if (previous == null || toAdd == null || toAdd == Boolean.FALSE) + return toAdd; + + if (previous instanceof ArrayList<?>) { + @SuppressWarnings("unchecked") + ArrayList<Object> prevArr = (ArrayList<Object>) previous; + if (!prevArr.contains(toAdd)) + prevArr.add(toAdd); + return previous; + } + if (previous.equals(toAdd)) + return previous; + + ArrayList<Object> arr = new ArrayList<Object>(); + arr.add(previous); + arr.add(toAdd); + return arr; + } + + protected Object getQueriedIDs(IEvaluationContext ctx, IExpression variable, String memberName, IExpression booleanExpr, Object queriedKeys) { + int type = booleanExpr.getExpressionType(); + switch (type) { + case IExpression.TYPE_EQUALS : + Binary eqExpr = (Binary) booleanExpr; + IExpression lhs = eqExpr.lhs; + IExpression rhs = eqExpr.rhs; + if (isIndexedMember(lhs, variable, memberName)) + return concatenateUnique(queriedKeys, rhs.evaluate(ctx)); + if (isIndexedMember(rhs, variable, memberName)) + return concatenateUnique(queriedKeys, lhs.evaluate(ctx)); + + // Not applicable for indexing + return null; + + case IExpression.TYPE_AND : + // AND is OK if at least one of the branches require the queried key + for (IExpression expr : ExpressionUtil.getOperands(booleanExpr)) { + Object test = getQueriedIDs(ctx, variable, memberName, expr, queriedKeys); + if (test != null) { + if (test == Boolean.FALSE) + // Failing exists so the AND will fail altogether + return test; + + // It's safe to break here since an and'ing several queries + // for different keys and the same input will yield false anyway. + return test; + } + } + return null; + + case IExpression.TYPE_OR : + // OR is OK if all the branches require the queried key + for (IExpression expr : ExpressionUtil.getOperands(booleanExpr)) { + Object test = getQueriedIDs(ctx, variable, memberName, expr, queriedKeys); + if (test == null) + // This branch did not require the key so index cannot be used + return null; + + if (test == Boolean.FALSE) + // Branch will always fail regardless of input, so just ignore + continue; + + queriedKeys = test; + } + return queriedKeys; + + case IExpression.TYPE_EXISTS : + case IExpression.TYPE_ALL : + // We must evaluate the lhs to find the referenced keys + // + CollectionFilter cf = (CollectionFilter) booleanExpr; + Iterator<?> values = cf.getOperand().evaluateAsIterator(ctx); + if (!values.hasNext()) + // No keys are requested but we know that an exists must + // fail at this point. An all will however succeed regardless + // of what is used as input. + return type == IExpression.TYPE_ALL ? null : Boolean.FALSE; + + LambdaExpression lambda = cf.lambda; + IEvaluationContext lambdaCtx = lambda.prolog(ctx); + Variable lambdaVar = lambda.getItemVariable(); + IExpression filterExpr = lambda.getOperand(); + do { + lambdaVar.setValue(lambdaCtx, values.next()); + queriedKeys = getQueriedIDs(lambdaCtx, variable, memberName, filterExpr, queriedKeys); + if (queriedKeys == null) + // No use continuing. The expression does not require the key + return null; + } while (values.hasNext()); + return queriedKeys; + } + return null; + } +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties index a70676f45..540b61526 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties @@ -48,6 +48,8 @@ only_format_specified_0=Only a format was specified: {0} only_max_and_empty_string_defaults_can_have_translations=Only max string and empty string defaults can have translations original_must_start_with_colon_0=Original version must start with colon: {0} original_stated_but_missing_0=Expected original version after colon: {0} +no_expression_factory=No Expression Factory service has been registered +no_expression_parser=No Expression Parser service has been registered pad_defined_more_then_once=Pad was defined more then once performing_subquery=Performing subquery premature_end_of_format=Premature end of format diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/IUPropertyQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/IUPropertyQuery.java index 95f3f3375..1013e91aa 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/IUPropertyQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/IUPropertyQuery.java @@ -11,38 +11,39 @@ package org.eclipse.equinox.internal.p2.metadata.query; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.query.ExpressionQuery; /** * 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. */ -public class IUPropertyQuery extends MatchQuery<IInstallableUnit> { - private String propertyName; - private String propertyValue; +public final class IUPropertyQuery extends ExpressionQuery<IInstallableUnit> { + public static final String ANY = "*"; //$NON-NLS-1$ - /** - * Creates a new query on the given property name and value. - */ - public IUPropertyQuery(String propertyName, String propertyValue) { - this.propertyName = propertyName; - this.propertyValue = propertyValue; - } + private static final IExpression matchTrueExpression = ExpressionUtil.parse("properties[$0] == true"); //$NON-NLS-1$ + private static final IExpression matchNullExpression = ExpressionUtil.parse("properties[$0] == null"); //$NON-NLS-1$ + private static final IExpression matchAnyExpression = ExpressionUtil.parse("properties[$0] != null"); //$NON-NLS-1$ + private static final IExpression matchValueExpression = ExpressionUtil.parse("properties[$0] == $1"); //$NON-NLS-1$ - /* (non-Javadoc) - * @see org.eclipse.equinox.p2.query2.Query#isMatch(java.lang.Object) - */ - public boolean isMatch(IInstallableUnit candidate) { + public static IMatchExpression<IInstallableUnit> createMatchExpression(String propertyName, String propertyValue) { + IExpressionFactory factory = ExpressionUtil.getFactory(); if (propertyName == null) - return true; - String value = getProperty(candidate, propertyName); - if (value != null && (value.equals(propertyValue) || propertyValue == null)) - return true; - return false; + return MATCH_ALL_UNITS; + if (propertyValue == null) + return factory.<IInstallableUnit> matchExpression(matchNullExpression, propertyName); + if (ANY.equals(propertyValue)) + return factory.<IInstallableUnit> matchExpression(matchAnyExpression, propertyName); + if (Boolean.valueOf(propertyValue).booleanValue()) + return factory.<IInstallableUnit> matchExpression(matchTrueExpression, propertyName); + return factory.<IInstallableUnit> matchExpression(matchValueExpression, propertyName, propertyValue); } - protected String getProperty(IInstallableUnit iu, String name) { - return iu.getProperty(name); + /** + * Creates a new query on the given property name and value. + */ + public IUPropertyQuery(String propertyName, String propertyValue) { + super(IInstallableUnit.class, createMatchExpression(propertyName, propertyValue)); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/LatestIUVersionQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/LatestIUVersionQuery.java index fe79d9404..1115e2e03 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/LatestIUVersionQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/LatestIUVersionQuery.java @@ -19,10 +19,23 @@ import org.eclipse.equinox.p2.query.*; */ public class LatestIUVersionQuery<T extends IVersionedId> extends ContextQuery<T> { + private final IQuery<T> query; + + public LatestIUVersionQuery() { + this.query = null; + } + + public LatestIUVersionQuery(IQuery<T> query) { + this.query = query; + } + /** * Performs the LatestIUVersionQuery */ public IQueryResult<T> perform(Iterator<T> iterator) { + if (query != null) + iterator = query.perform(iterator).iterator(); + HashMap<String, T> greatestIUVersion = new HashMap<String, T>(); while (iterator.hasNext()) { T versionedID = iterator.next(); diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/UpdateQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/UpdateQuery.java index 3ca68f9a0..61f97c47f 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/UpdateQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/UpdateQuery.java @@ -10,19 +10,14 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.metadata.query; -import org.eclipse.equinox.p2.metadata.IUpdateDescriptor; - -import org.eclipse.equinox.p2.metadata.IInstallableUnitPatch; - -import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.metadata.*; import org.eclipse.equinox.p2.query.MatchQuery; /** * A query that finds all IUs that are considered an "Update" of the * specified IU. */ -public class UpdateQuery extends MatchQuery<IInstallableUnit> { +public final class UpdateQuery extends MatchQuery<IInstallableUnit> { private IInstallableUnit updateFrom; public UpdateQuery(IInstallableUnit updateFrom) { diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/ExpressionUtil.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/ExpressionUtil.java index 84d48eb3e..eb1adc5af 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/ExpressionUtil.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/ExpressionUtil.java @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.expression; +import org.eclipse.equinox.internal.p2.metadata.MetadataActivator; import org.eclipse.equinox.internal.p2.metadata.expression.*; -import org.eclipse.equinox.internal.p2.metadata.expression.parser.ExpressionParser; import org.eclipse.equinox.internal.p2.metadata.expression.parser.LDAPFilterParser; /** @@ -20,22 +20,23 @@ import org.eclipse.equinox.internal.p2.metadata.expression.parser.LDAPFilterPars */ public abstract class ExpressionUtil { private static final LDAPFilterParser ldapFilterParser = new LDAPFilterParser(ExpressionFactory.INSTANCE); - private static final ExpressionParser expressionParser = new ExpressionParser(ExpressionFactory.INSTANCE); + public static final IExpression TRUE_EXPRESSION = getFactory().constant(Boolean.TRUE); + public static final IExpression FALSE_EXPRESSION = getFactory().constant(Boolean.FALSE); /** * Returns the global expression factory * @return The global expression factory. */ public static IExpressionFactory getFactory() { - return ExpressionFactory.INSTANCE; + return MetadataActivator.getExpressionFactory(); } /** * Creates and returns a new expression parser * @return The new parser */ - public static IExpressionParser newParser() { - return new ExpressionParser(getFactory()); + public static IExpressionParser getParser() { + return MetadataActivator.getExpressionParser(); } /** @@ -59,7 +60,7 @@ public abstract class ExpressionUtil { */ public static IExpression parse(String expression) { expression = trimmedOrNull(expression); - return expression == null ? null : expressionParser.parse(expression); + return expression == null ? null : getParser().parse(expression); } /** diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IContextExpression.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IContextExpression.java new file mode 100644 index 000000000..7dc24dd03 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IContextExpression.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009 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 + *******************************************************************************/ +package org.eclipse.equinox.p2.metadata.expression; + +import java.util.Iterator; + +/** + * This is an expression that will need access to the global variable + * <code>everything</code>. + */ +public interface IContextExpression<T> extends IExpression { + /** + * <p>Creates a new context to be passed to a subsequent evaluation. The context + * will have the variable 'everything' set to an expression that represents + * the <code>everything</code> iterator filtered for instances of <code>elementClass</code>.</p> + * <p>The values of the iterator will be copied if necessary (when everything is referenced + * more then once).</p> + * @param elementClass the class of the iterator elements + * @param everything The iterator that represents all queried material. + * @return A new evaluation context. + */ + IEvaluationContext createContext(Class<T> elementClass, Iterator<T> everything); + + /** + * Returns the parameters that this context expression was created with. + * @return An array of parameters, possibly empty but never <code>null</code>. + */ + Object[] getParameters(); + + /** + * Evaluate the expression and return the expected collection result as an iterator + * @param context The evaluation context + * @return The result of the evaluation. + */ + Iterator<T> iterator(IEvaluationContext context); +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IEvaluationContext.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IEvaluationContext.java index 4b049c054..ee3021442 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IEvaluationContext.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IEvaluationContext.java @@ -10,12 +10,18 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.expression; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; + /** * The evaluation context. Contexts can be nested and new contexts are pushed for each closure * during an evaluation of an expression. * @since 2.0 */ public interface IEvaluationContext { + IIndexProvider<?> getIndexProvider(); + + void setIndexProvider(IIndexProvider<?> indexProvider); + /** * Retrieve the value of the given <code>variable</code> from this context * @param variable The variable who's value should be retrieved diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionFactory.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionFactory.java index 47d214619..f7e275df0 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionFactory.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionFactory.java @@ -74,6 +74,14 @@ public interface IExpressionFactory { IExpression constant(Object value); /** + * Creates a top level expression that represents a full query. + * @param expr The query + * @param parameters The parameters of the query + * @return A top level query expression + */ + <T> IContextExpression<T> contextExpression(IExpression expr, Object... parameters); + + /** * Create an expression that tests if <code>lhs</code> is equal to <code>rhs</code>. * @param lhs The left hand side value. * @param rhs The right hand side value. diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionParser.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionParser.java index 6e716af06..c9f43b33c 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionParser.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/expression/IExpressionParser.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.expression; + /** * A parser that produces an expression tree based on a string representation. An * implementation will use the {@link IExpressionFactory} to create the actual expressions @@ -18,9 +19,19 @@ package org.eclipse.equinox.p2.metadata.expression; public interface IExpressionParser { /** * Create a new expression. The expression will have access to the global - * variable and to the context parameters. + * variable 'this' and to the context parameters. * @param exprString The string representing the boolean expression. * @return The resulting expression tree. + * @throws ExpressionParseException */ IExpression parse(String exprString); + + /** + * Create an arbitrary expression. The expression will have access to the global + * variable 'everything' and to the context parameters. + * @param exprString The string representing the boolean expression. + * @return The resulting expression tree. + * @throws ExpressionParseException + */ + IExpression parseQuery(String exprString); } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IIndex.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IIndex.java new file mode 100644 index 000000000..b06ea05c0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IIndex.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.p2.metadata.index; + +import java.util.Iterator; +import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.expression.IExpression; + +/** + * Indexed access to the elements provided by an IQueryable + */ +public interface IIndex<T> { + /** + * Obtains the elements that are candidates for the given <code>booleanExpr</code> when applied + * using the given <code>variable</code> as <code>this</code>. + * The returned set of elements are the elements that must be present in order for the expression + * to evaluate to <code>true</code>. The set may contain false positives. + * + * TODO: Write more about how the valid set of elements is determined. + * + * @param ctx The evaluation context used when examining the <code>booleanExpr</code>. + * @param variable The variable used as <code>this</code>. + * @param booleanExpr The boolean expression. + * @return The candidate elements or <code>null</code> if this index cannot be used. + */ + Iterator<T> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr); +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/ObjectMatchQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IIndexProvider.java index f48e50aac..543acbdaf 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/query/ObjectMatchQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IIndexProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Cloudsmith Inc. and others. + * Copyright (c) 2010 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 @@ -8,15 +8,12 @@ * Contributors: * Cloudsmith Inc. - initial API and implementation *******************************************************************************/ -package org.eclipse.equinox.internal.p2.metadata.query; +package org.eclipse.equinox.p2.metadata.index; -import org.eclipse.equinox.p2.query.MatchQuery; +import java.util.Iterator; -/** - * Special implementation for use without generic support - */ -public abstract class ObjectMatchQuery extends MatchQuery<Object> { - public boolean isMatch(Object candidate) { - return true; - } +public interface IIndexProvider<T> { + IIndex<T> getIndex(String memberName); + + Iterator<T> everything(); } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IQueryWithIndex.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IQueryWithIndex.java new file mode 100644 index 000000000..672b5df89 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/index/IQueryWithIndex.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.p2.metadata.index; + +import org.eclipse.equinox.p2.query.IQuery; +import org.eclipse.equinox.p2.query.IQueryResult; + +public interface IQueryWithIndex<T> extends IQuery<T> { + IQueryResult<T> perform(IIndexProvider<T> indexProvider); +} diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryMemberQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryMemberQuery.java index dc59f605b..22bd85835 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryMemberQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryMemberQuery.java @@ -10,11 +10,8 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.query; -import java.util.Collection; -import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.IRequirement; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.expression.*; /** * A query matching every {@link IInstallableUnit} that is a member @@ -22,8 +19,13 @@ import org.eclipse.equinox.p2.query.MatchQuery; * * @since 2.0 */ -public class CategoryMemberQuery extends MatchQuery<IInstallableUnit> { - private final Collection<IRequirement> required; +public final class CategoryMemberQuery extends ExpressionQuery<IInstallableUnit> { + private static final IExpression expression = ExpressionUtil.parse("$0.exists(r | $0 ~= this"); //$NON-NLS-1$ + + private static IMatchExpression<IInstallableUnit> createExpression(IInstallableUnit category) { + IExpressionFactory factory = ExpressionUtil.getFactory(); + return CategoryQuery.isCategory(category) ? factory.<IInstallableUnit> matchExpression(expression, category.getRequiredCapabilities()) : MATCH_NO_UNIT; + } /** * Creates a new query that will return the members of the @@ -33,23 +35,6 @@ public class CategoryMemberQuery extends MatchQuery<IInstallableUnit> { * @param category The category */ public CategoryMemberQuery(IInstallableUnit category) { - if (CategoryQuery.isCategory(category)) - this.required = category.getRequiredCapabilities(); - else - this.required = CollectionUtils.emptyList(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.equinox.internal.provisional.p2.metadata.query.MatchQuery#isMatch(java.lang.Object) - */ - public boolean isMatch(IInstallableUnit candidate) { - // since a category lists its members as requirements, then meeting - // any requirement means the candidate is a member of the category. - for (IRequirement req : required) { - if (candidate.satisfies(req)) - return true; - } - return false; + super(IInstallableUnit.class, createExpression(category)); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryQuery.java index d1d86f912..f93fbb4ab 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/CategoryQuery.java @@ -12,22 +12,16 @@ package org.eclipse.equinox.p2.metadata.query; import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.query.MatchQuery; /** * A query matching every {@link IInstallableUnit} that is a category. * @since 2.0 */ -public final class CategoryQuery extends MatchQuery<IInstallableUnit> { +public final class CategoryQuery extends ExpressionQuery<IInstallableUnit> { private static final String PROP_TYPE_CATEGORY = "org.eclipse.equinox.p2.type.category"; //$NON-NLS-1$ - private IUPropertyQuery query; public CategoryQuery() { - query = new IUPropertyQuery(PROP_TYPE_CATEGORY, null); - } - - public boolean isMatch(IInstallableUnit candidate) { - return query.isMatch(candidate); + super(IInstallableUnit.class, IUPropertyQuery.createMatchExpression(PROP_TYPE_CATEGORY, Boolean.TRUE.toString())); } /** diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/ExpressionQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/ExpressionQuery.java index 90624c637..345ed618b 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/ExpressionQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/ExpressionQuery.java @@ -10,30 +10,66 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.query; +import java.util.HashSet; +import java.util.Iterator; +import org.eclipse.equinox.internal.p2.metadata.expression.Expression; import org.eclipse.equinox.internal.p2.metadata.expression.ExpressionFactory; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.expression.*; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.index.*; +import org.eclipse.equinox.p2.query.*; /** * A query that matches candidates against an expression. * @since 2.0 */ -public class ExpressionQuery<T> extends MatchQuery<T> { +public class ExpressionQuery<T> implements IQueryWithIndex<T> { + public static final IMatchExpression<IInstallableUnit> MATCH_ALL_UNITS = ExpressionUtil.getFactory().matchExpression(ExpressionUtil.TRUE_EXPRESSION); + public static final IMatchExpression<IInstallableUnit> MATCH_NO_UNIT = ExpressionUtil.getFactory().matchExpression(ExpressionUtil.FALSE_EXPRESSION); + private final IMatchExpression<T> expression; - private final IEvaluationContext context; - private final Class<T> matchingClass; + private final Class<? extends T> matchingClass; + private IEvaluationContext context; - public ExpressionQuery(Class<T> matchingClass, IExpression expression, Object... parameters) { + public ExpressionQuery(Class<? extends T> matchingClass, IExpression expression, Object... parameters) { this(matchingClass, ExpressionUtil.getFactory().<T> matchExpression(expression, parameters)); } - public ExpressionQuery(Class<T> matchingClass, IMatchExpression<T> expression) { + public ExpressionQuery(Class<? extends T> matchingClass, IMatchExpression<T> expression) { this.matchingClass = matchingClass; this.expression = expression; this.context = expression.createContext(); } - @Override + public IQueryResult<T> perform(IIndexProvider<T> indexProvider) { + Iterator<T> iterator = null; + for (String member : Expression.getIndexCandidateMembers(IArtifactKey.class, ExpressionFactory.THIS, (Expression) expression)) { + IIndex<T> index = indexProvider.getIndex(member); + if (index != null) { + iterator = index.getCandidates(context, ExpressionFactory.THIS, expression); + if (iterator != null) + break; + } + } + if (iterator == null) + iterator = indexProvider.everything(); + return perform(iterator); + } + + public IQueryResult<T> perform(Iterator<T> iterator) { + HashSet<T> result = null; + while (iterator.hasNext()) { + T value = iterator.next(); + if (isMatch(value)) { + if (result == null) + result = new HashSet<T>(); + result.add(value); + } + } + return result == null ? Collector.<T> emptyCollector() : new CollectionResult<T>(result); + } + public boolean isMatch(T candidate) { if (!matchingClass.isInstance(candidate)) return false; @@ -44,4 +80,8 @@ public class ExpressionQuery<T> extends MatchQuery<T> { public IMatchExpression<T> getExpression() { return expression; } + + public void setIndexProvider(IIndexProvider<T> indexProvider) { + context.setIndexProvider(indexProvider); + } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/FragmentQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/FragmentQuery.java index fc70dd9e9..de04066a3 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/FragmentQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/FragmentQuery.java @@ -10,26 +10,16 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.query; -import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment; - -import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment; /** * A query matching every {@link IInstallableUnit} that is a category. * @since 2.0 */ -public final class FragmentQuery extends MatchQuery<IInstallableUnit> { - private static final String PROP_TYPE_FRAGMENT = "org.eclipse.equinox.p2.type.fragment"; //$NON-NLS-1$ - private IUPropertyQuery query; - +public final class FragmentQuery extends ExpressionQuery<IInstallableUnit> { public FragmentQuery() { - query = new IUPropertyQuery(PROP_TYPE_FRAGMENT, null); - } - - public boolean isMatch(IInstallableUnit candidate) { - return query.isMatch(candidate); + super(IInstallableUnitFragment.class, MATCH_ALL_UNITS); } /** @@ -38,11 +28,8 @@ public final class FragmentQuery extends MatchQuery<IInstallableUnit> { * @return <tt>true</tt> if the parameter is a fragment. */ public static boolean isFragment(IInstallableUnit iu) { - if (iu instanceof IInstallableUnitFragment) - return true; + return iu instanceof IInstallableUnitFragment; // String value = iu.getProperty(PROP_TYPE_FRAGMENT); - // if (value != null && (value.equals(Boolean.TRUE.toString()))) - // return true; - return false; + // return value != null && (value.equals(Boolean.TRUE.toString())); } } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/GroupQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/GroupQuery.java index 298b04a2f..729920902 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/GroupQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/GroupQuery.java @@ -12,22 +12,16 @@ package org.eclipse.equinox.p2.metadata.query; import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.query.MatchQuery; /** * A query matching every {@link IInstallableUnit} that is a group. * @since 2.0 */ -public final class GroupQuery extends MatchQuery<IInstallableUnit> { +public final class GroupQuery extends ExpressionQuery<IInstallableUnit> { private static final String PROP_TYPE_GROUP = "org.eclipse.equinox.p2.type.group"; //$NON-NLS-1$ - private IUPropertyQuery query; public GroupQuery() { - query = new IUPropertyQuery(PROP_TYPE_GROUP, null); - } - - public boolean isMatch(IInstallableUnit candidate) { - return query.isMatch(candidate); + super(IInstallableUnit.class, IUPropertyQuery.createMatchExpression(PROP_TYPE_GROUP, Boolean.TRUE.toString())); } /** diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/InstallableUnitQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/InstallableUnitQuery.java index ac2110b03..42f5c9915 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/InstallableUnitQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/InstallableUnitQuery.java @@ -10,26 +10,39 @@ *******************************************************************************/ package org.eclipse.equinox.p2.metadata.query; -import org.eclipse.equinox.p2.metadata.Version; -import org.eclipse.equinox.p2.metadata.VersionRange; - -import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.metadata.IVersionedId; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.expression.*; /** * A query that matches on the id and version of an {@link IInstallableUnit}. * @since 2.0 */ -public class InstallableUnitQuery extends MatchQuery<IInstallableUnit> { +public final class InstallableUnitQuery extends ExpressionQuery<IInstallableUnit> { /** * A convenience query that will match any {@link IInstallableUnit} * it encounters. */ public static final InstallableUnitQuery ANY = new InstallableUnitQuery((String) null); - private String id; - private final VersionRange range; + private static final IExpression matchID = ExpressionUtil.parse("id == $0"); //$NON-NLS-1$ + private static final IExpression matchIDAndVersion = ExpressionUtil.parse("id == $0 && version == $1"); //$NON-NLS-1$ + private static final IExpression matchIDAndRange = ExpressionUtil.parse("id == $0 && version ~= $1"); //$NON-NLS-1$ + + private static IMatchExpression<IInstallableUnit> createMatchExpression(String id) { + return id == null ? ExpressionQuery.MATCH_ALL_UNITS : ExpressionUtil.getFactory().<IInstallableUnit> matchExpression(matchID, id); + } + + private static IMatchExpression<IInstallableUnit> createMatchExpression(String id, VersionRange range) { + if (range == null || range.equals(VersionRange.emptyRange)) + return createMatchExpression(id); + if (range.getMinimum().equals(range.getMaximum())) + return createMatchExpression(id, range.getMinimum()); + return id == null ? ExpressionQuery.MATCH_ALL_UNITS : ExpressionUtil.getFactory().<IInstallableUnit> matchExpression(matchIDAndRange, id, range); + } + + private static IMatchExpression<IInstallableUnit> createMatchExpression(String id, Version version) { + return version == null || version.equals(Version.emptyVersion) ? createMatchExpression(id) : ExpressionUtil.getFactory().<IInstallableUnit> matchExpression(matchIDAndVersion, id, version); + } /** * Creates a query that will match any {@link IInstallableUnit} with the given @@ -38,8 +51,7 @@ public class InstallableUnitQuery extends MatchQuery<IInstallableUnit> { * @param id The installable unit id to match, or <code>null</code> to match any id */ public InstallableUnitQuery(String id) { - this.id = id; - this.range = null; + super(IInstallableUnit.class, createMatchExpression(id)); } /** @@ -50,8 +62,7 @@ public class InstallableUnitQuery extends MatchQuery<IInstallableUnit> { * @param range The version range to match */ public InstallableUnitQuery(String id, VersionRange range) { - this.id = id; - this.range = range; + super(IInstallableUnit.class, createMatchExpression(id, range)); } /** @@ -62,8 +73,7 @@ public class InstallableUnitQuery extends MatchQuery<IInstallableUnit> { * @param version The precise version that a matching unit must have */ public InstallableUnitQuery(String id, Version version) { - this.id = id; - this.range = (version == null || Version.emptyVersion.equals(version)) ? null : new VersionRange(version, true, version, true); + super(IInstallableUnit.class, createMatchExpression(id, version)); } /** @@ -81,26 +91,7 @@ public class InstallableUnitQuery extends MatchQuery<IInstallableUnit> { * @return The installable unit it */ public String getId() { - return id; + Object[] params = getExpression().getParameters(); + return params.length > 0 ? (String) params[0] : null; } - - /** - * Returns the version range that this query will match against. - * @return The installable unit version range. - */ - public VersionRange getRange() { - return range; - } - - /* (non-Javadoc) - * @see org.eclipse.equinox.p2.query2.Query#isMatch(java.lang.Object) - */ - public boolean isMatch(IInstallableUnit candidate) { - if (id != null && !id.equals(candidate.getId())) - return false; - if (range != null && !range.isIncluded(candidate.getVersion())) - return false; - return true; - } - } diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/PatchQuery.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/PatchQuery.java index d066db376..e341d8efc 100644 --- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/PatchQuery.java +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/query/PatchQuery.java @@ -12,22 +12,16 @@ package org.eclipse.equinox.p2.metadata.query; import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.query.MatchQuery; /** * A query matching every {@link IInstallableUnit} that is a patch. * @since 2.0 */ -public final class PatchQuery extends MatchQuery<IInstallableUnit> { +public final class PatchQuery extends ExpressionQuery<IInstallableUnit> { private static final String PROP_TYPE_PATCH = "org.eclipse.equinox.p2.type.patch"; //$NON-NLS-1$ - private IUPropertyQuery query; public PatchQuery() { - query = new IUPropertyQuery(PROP_TYPE_PATCH, Boolean.TRUE.toString()); - } - - public boolean isMatch(IInstallableUnit candidate) { - return query.isMatch(candidate); + super(IInstallableUnit.class, IUPropertyQuery.createMatchExpression(PROP_TYPE_PATCH, Boolean.TRUE.toString())); } /** diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/query/CollectionResult.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/query/CollectionResult.java new file mode 100644 index 000000000..688fd651d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/query/CollectionResult.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.equinox.p2.query; + +import java.lang.reflect.Array; +import java.util.*; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; + +public class CollectionResult<T> implements IQueryResult<T> { + private final Collection<T> collection; + + public CollectionResult(Collection<T> collection) { + this.collection = collection == null ? CollectionUtils.<T> emptySet() : collection; + } + + public IQueryResult<T> query(IQuery<T> query, IProgressMonitor monitor) { + return query.perform(iterator()); + } + + public boolean isEmpty() { + return collection.isEmpty(); + } + + public Iterator<T> iterator() { + return collection.iterator(); + } + + public T[] toArray(Class<? extends T> clazz) { + int size = collection.size(); + @SuppressWarnings("unchecked") + T[] result = (T[]) Array.newInstance(clazz, size); + if (size != 0) + collection.toArray(result); + return result; + } + + public Set<T> toSet() { + return new HashSet<T>(collection); + } + + public Set<T> unmodifiableSet() { + return collection instanceof Set<?> ? Collections.<T> unmodifiableSet((Set<T>) collection) : toSet(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java index 56999c5c6..c251d5279 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java @@ -495,8 +495,10 @@ public abstract class AbstractPublisherAction implements IPublisherAction { */ protected IInstallableUnit queryForIU(IPublisherResult publisherResult, String iuId, Version version) { IQuery<IInstallableUnit> query = new InstallableUnitQuery(iuId, version); - IQueryResult<IInstallableUnit> collector = Collector.emptyCollector(); + if (version == null || Version.emptyVersion.equals(version)) + query = new LatestIUVersionQuery<IInstallableUnit>(query); + IQueryResult<IInstallableUnit> collector = Collector.emptyCollector(); NullProgressMonitor progress = new NullProgressMonitor(); if (publisherResult != null) collector = publisherResult.query(query, progress); @@ -504,11 +506,6 @@ public abstract class AbstractPublisherAction implements IPublisherAction { collector = info.getMetadataRepository().query(query, progress); if (collector.isEmpty() && info.getContextMetadataRepository() != null) collector = info.getContextMetadataRepository().query(query, progress); - - if (version == null || Version.emptyVersion.equals(version)) { - query = new LatestIUVersionQuery<IInstallableUnit>(); - collector = collector.query(query, null); - } if (!collector.isEmpty()) return collector.iterator().next(); return null; diff --git a/bundles/org.eclipse.equinox.p2.ql/.project b/bundles/org.eclipse.equinox.p2.ql/.project index 6140e1be9..bf129f044 100644 --- a/bundles/org.eclipse.equinox.p2.ql/.project +++ b/bundles/org.eclipse.equinox.p2.ql/.project @@ -25,6 +25,11 @@ <arguments> </arguments> </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ds.core.builder</name> + <arguments> + </arguments> + </buildCommand> </buildSpec> <natures> <nature>org.eclipse.jdt.core.javanature</nature> diff --git a/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF index 5d307b505..7e0335f87 100644 --- a/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Import-Package: org.eclipse.equinox.internal.p2.core.helpers, org.eclipse.equinox.internal.provisional.p2.metadata, org.eclipse.equinox.p2.metadata, org.eclipse.equinox.p2.metadata.expression, + org.eclipse.equinox.p2.metadata.index, org.eclipse.equinox.p2.metadata.query, org.eclipse.equinox.p2.query, org.eclipse.equinox.p2.repository.artifact, @@ -26,3 +27,4 @@ Export-Package: org.eclipse.equinox.internal.p2.ql.expression;x-internal:=true, org.eclipse.equinox.p2.ql Bundle-Activator: org.eclipse.equinox.internal.p2.ql.QLActivator Require-Bundle: org.eclipse.equinox.common;bundle-version="3.5.1" +Service-Component: OSGI-INF/qlFactory.xml, OSGI-INF/qlParser.xml diff --git a/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlFactory.xml b/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlFactory.xml new file mode 100644 index 000000000..407aa9704 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlFactory.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.equinox.p2.ql.factory"> + <implementation class="org.eclipse.equinox.internal.p2.ql.expression.QLFactory"/> + <service> + <provide interface="org.eclipse.equinox.p2.metadata.expression.IExpressionFactory"/> + </service> + <property name="service.priority" type="Integer" value="2"/> +</scr:component> diff --git a/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlParser.xml b/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlParser.xml new file mode 100644 index 000000000..8617fa747 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/OSGI-INF/qlParser.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.equinox.p2.ql.parser"> + <implementation class="org.eclipse.equinox.internal.p2.ql.parser.QLParser"/> + <service> + <provide interface="org.eclipse.equinox.p2.metadata.expression.IExpressionParser"/> + </service> +</scr:component>
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/build.properties b/bundles/org.eclipse.equinox.p2.ql/build.properties index 06b4caead..e0cf562f5 100644 --- a/bundles/org.eclipse.equinox.p2.ql/build.properties +++ b/bundles/org.eclipse.equinox.p2.ql/build.properties @@ -2,17 +2,19 @@ # <copyright> # </copyright> # -# $Id: build.properties,v 1.2 2009/12/29 11:09:34 thallgren Exp $ +# $Id: build.properties,v 1.3 2010/01/23 22:21:13 johna Exp $ bin.includes = .,\ META-INF/,\ plugin.properties,\ - about.html + about.html,\ + OSGI-INF/ jars.compile.order = . source.. = src/ output.. = bin/ src.includes = about.html,\ - model/ + model/,\ + OSGI-INF/ javacTarget=jsr14 javacSource=1.5 -javacWarnings..=+fieldHiding
\ No newline at end of file +javacWarnings..=+fieldHiding diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/ContextExpression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/ContextExpression.java index 26cbce481..e7c3bc7ec 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/ContextExpression.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/ContextExpression.java @@ -12,8 +12,8 @@ package org.eclipse.equinox.internal.p2.ql.expression; import java.util.Iterator; import org.eclipse.equinox.internal.p2.metadata.expression.*; -import org.eclipse.equinox.internal.p2.ql.Everything; -import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.expression.IExpression; import org.eclipse.equinox.p2.ql.IContextExpression; import org.eclipse.equinox.p2.ql.ITranslationSupport; @@ -22,71 +22,17 @@ import org.eclipse.equinox.p2.ql.ITranslationSupport; * variable 'everything' and initialized it with the iterator that represents all * available items. */ -public final class ContextExpression<T> extends Unary implements IContextExpression<T>, IQLConstants { - private static final Object[] noParams = new Object[0]; - private final Class<T> elementClass; - private final Object[] parameters; - - public ContextExpression(Class<T> elementClass, Expression expression, Object[] parameters) { - super(expression); - this.elementClass = elementClass; - this.parameters = parameters == null ? noParams : parameters; - } - - public boolean accept(IExpressionVisitor visitor) { - return visitor.visit(operand); - } - - public void toString(StringBuffer bld, Variable rootVariable) { - operand.toString(bld, rootVariable); - } - - public IEvaluationContext createContext(Iterator<T> iterator) { - Variable everything = QLFactory.EVERYTHING; - IEvaluationContext context = EvaluationContext.create(parameters, everything); - context.setValue(everything, new Everything<T>(elementClass, iterator, QLUtil.needsRepeadedAccessToEverything(operand))); - return context; +public final class ContextExpression<T> extends org.eclipse.equinox.internal.p2.metadata.expression.ContextExpression<T> implements IContextExpression<T> { + public ContextExpression(Expression expression, Object[] parameters) { + super(expression, parameters); } - public IEvaluationContext createContext(Iterator<T> iterator, ITranslationSupport ts) { - Variable everything = QLFactory.EVERYTHING; + public IEvaluationContext createContext(Class<T> elementClass, Iterator<T> iterator, ITranslationSupport ts) { + Variable everything = ExpressionFactory.EVERYTHING; IExpression translations = QLFactory.TRANSLATIONS; IEvaluationContext context = EvaluationContext.create(parameters, new IExpression[] {everything, translations}); - context.setValue(everything, new Everything<T>(elementClass, iterator, QLUtil.needsRepeadedAccessToEverything(operand))); + context.setValue(everything, new Everything<T>(elementClass, iterator, operand)); context.setValue(translations, ts); return context; } - - public Class<T> getElementClass() { - return elementClass; - } - - public int getExpressionType() { - return 0; - } - - public String getOperator() { - throw new UnsupportedOperationException(); - } - - public int getPriority() { - return operand.getPriority(); - } - - public Object[] getParameters() { - return parameters; - } - - public int hashCode() { - return operand.hashCode(); - } - - @SuppressWarnings("unchecked") - public Iterator<T> iterator(IEvaluationContext context) { - return (Iterator<T>) evaluateAsIterator(context); - } - - public void toString(StringBuffer bld) { - toString(bld, QLFactory.EVERYTHING); - } } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Flatten.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Flatten.java index b0ff4122c..8aa33622c 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Flatten.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Flatten.java @@ -10,9 +10,10 @@ *******************************************************************************/ package org.eclipse.equinox.internal.p2.ql.expression; +import org.eclipse.equinox.internal.p2.metadata.expression.CompoundIterator; + import java.util.Iterator; import org.eclipse.equinox.internal.p2.metadata.expression.Expression; -import org.eclipse.equinox.internal.p2.ql.FlattenIterator; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; /** @@ -25,7 +26,7 @@ final class Flatten extends UnaryCollectionFilter { } public Iterator<?> evaluateAsIterator(IEvaluationContext context) { - return new FlattenIterator<Object>(operand.evaluateAsIterator(context)); + return new CompoundIterator<Object>(operand.evaluateAsIterator(context)); } public int getExpressionType() { diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLFactory.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLFactory.java index 17bbb657a..8568e680c 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLFactory.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLFactory.java @@ -5,15 +5,12 @@ import java.lang.reflect.InvocationTargetException; import java.util.*; import org.eclipse.equinox.internal.p2.metadata.expression.*; import org.eclipse.equinox.p2.metadata.expression.IExpression; -import org.eclipse.equinox.p2.ql.IContextExpression; import org.eclipse.equinox.p2.ql.IQLFactory; public class QLFactory extends ExpressionFactory implements IQLFactory, IQLConstants { @SuppressWarnings("hiding") public static final IQLFactory INSTANCE = new QLFactory(); - public static final Variable EVERYTHING = new Variable(IExpressionConstants.VARIABLE_EVERYTHING); - public static final Variable TRANSLATIONS = new Variable(VARIABLE_TRANSLATIONS); protected static final Map<String, Constructor<?>> functionMap; @@ -60,8 +57,8 @@ public class QLFactory extends ExpressionFactory implements IQLFactory, IQLConst return new Condition((Expression) test, (Expression) ifTrue, (Expression) ifFalse); } - public <T> IContextExpression<T> contextExpression(Class<T> elementClass, IExpression expr, Object... parameters) { - return new ContextExpression<T>(elementClass, (Expression) expr, parameters); + public <T> org.eclipse.equinox.p2.metadata.expression.IContextExpression<T> contextExpression(IExpression expr, Object... parameters) { + return new ContextExpression<T>((Expression) expr, parameters); } public IExpression first(IExpression collection, IExpression lambda) { diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLUtil.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLUtil.java index 6d790b25b..5ae9b8c6b 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLUtil.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/QLUtil.java @@ -73,24 +73,4 @@ public abstract class QLUtil implements IExpression, IQLConstants { }); return translationSupportNeeded[0]; } - - /** - * Checks if the expression will make repeated requests for the 'everything' iterator. - * @return <code>true</code> if repeated requests will be made, <code>false</code> if not. - */ - static boolean needsRepeadedAccessToEverything(Expression expression) { - final boolean[] repeatedAccessNeeded = new boolean[] {false}; - expression.accept(new IExpressionVisitor() { - public boolean visit(IExpression expr) { - // FIXME Needs proper counting - if (expr == QLFactory.EVERYTHING) { - repeatedAccessNeeded[0] = true; - return false; - } - return true; - } - }); - // return repeatedAccessNeeded[0]; - return true; - } } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Select.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Select.java index 9ea863a0e..300d8d390 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Select.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Select.java @@ -12,7 +12,6 @@ package org.eclipse.equinox.internal.p2.ql.expression; import java.util.Iterator; import org.eclipse.equinox.internal.p2.metadata.expression.*; -import org.eclipse.equinox.internal.p2.ql.MatchIteratorFilter; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; import org.eclipse.equinox.p2.ql.IQLExpression; diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Unique.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Unique.java index 5d4953cea..270ac2b5e 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Unique.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/expression/Unique.java @@ -12,7 +12,6 @@ package org.eclipse.equinox.internal.p2.ql.expression; import java.util.*; import org.eclipse.equinox.internal.p2.metadata.expression.*; -import org.eclipse.equinox.internal.p2.ql.MatchIteratorFilter; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; import org.eclipse.equinox.p2.ql.IQLExpression; @@ -21,8 +20,12 @@ import org.eclipse.equinox.p2.ql.IQLExpression; * once throughout the whole query. */ final class Unique extends Binary implements IQLConstants, IQLExpression { + /** + * A UniqueIterator that uses a set as a discriminator, ensuring that + * no element is returned twice. + */ static class UniqueIterator<T> extends MatchIteratorFilter<T> { - private final Set<T> uniqueSet; + final Set<T> uniqueSet; public UniqueIterator(Iterator<? extends T> iterator, Set<T> uniqueSet) { super(iterator); diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/parser/QLParser.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/parser/QLParser.java index 9a281dfd8..712e94a14 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/parser/QLParser.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/parser/QLParser.java @@ -11,7 +11,6 @@ package org.eclipse.equinox.internal.p2.ql.parser; import java.util.*; -import org.eclipse.equinox.internal.p2.metadata.expression.IExpressionConstants; import org.eclipse.equinox.internal.p2.metadata.expression.Variable; import org.eclipse.equinox.internal.p2.metadata.expression.parser.ExpressionParser; import org.eclipse.equinox.internal.p2.ql.expression.IQLConstants; @@ -56,28 +55,6 @@ public class QLParser extends ExpressionParser implements IQLParser, IQLConstant qlKeywords.put(OPERATOR_EACH, new Integer(TOKEN_ANY)); } - public QLParser(IQLFactory factory) { - super(factory); - } - - public synchronized IExpression parseQuery(String exprString) { - expression = exprString; - tokenPos = 0; - currentToken = 0; - tokenValue = null; - rootVariable = IExpressionConstants.VARIABLE_EVERYTHING; - IExpression everythingVariable = factory.variable(IExpressionConstants.VARIABLE_EVERYTHING); - push(everythingVariable); - try { - nextToken(); - IExpression expr = parseCondition(); - assertToken(TOKEN_END); - return expr; - } finally { - popVariable(); // pop context - } - } - protected Map<String, Integer> keywordToTokenMap() { return qlKeywords; } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IContextExpression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IContextExpression.java index fa0468f0f..fa588b58e 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IContextExpression.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IContextExpression.java @@ -12,24 +12,12 @@ package org.eclipse.equinox.p2.ql; import java.util.Iterator; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; -import org.eclipse.equinox.p2.metadata.expression.IExpression; /** * This is an expression that will need access to the global variable * <code>everything</code>. */ -public interface IContextExpression<T> extends IExpression { - /** - * <p>Creates a new context to be passed to a subsequent evaluation. The context - * will have the variable 'everything' set to an expression that represents - * the <code>everything</code> iterator filtered for instances of <code>elementClass</code>.</p> - * <p>The values of the iterator will be copied if necessary (when everything is referenced - * more then once).</p> - * @param everything The iterator that represents all queried material. - * @return A new evaluation context. - */ - IEvaluationContext createContext(Iterator<T> everything); - +public interface IContextExpression<T> extends org.eclipse.equinox.p2.metadata.expression.IContextExpression<T> { /** * <p>Creates a new context to be passed to a subsequent evaluation. The context * will have the variable 'everything' set to an expression that represents @@ -40,24 +28,5 @@ public interface IContextExpression<T> extends IExpression { * @param translations A translation support object to be assigned to the variable 'translations' * @return A new evaluation context. */ - IEvaluationContext createContext(Iterator<T> everything, ITranslationSupport translations); - - /** - * Returns the element class - * @return The element class - */ - Class<T> getElementClass(); - - /** - * Returns the parameters that this context expression was created with. - * @return An array of parameters, possibly empty but never <code>null</code>. - */ - Object[] getParameters(); - - /** - * Evaluate the expression and return the expected collection result as an iterator - * @param context The evaluation context - * @return The result of the evaluation. - */ - Iterator<T> iterator(IEvaluationContext context); + IEvaluationContext createContext(Class<T> elementClass, Iterator<T> everything, ITranslationSupport translations); } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IQLFactory.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IQLFactory.java index 501dff83f..8afa1822f 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IQLFactory.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/IQLFactory.java @@ -55,15 +55,6 @@ public interface IQLFactory extends IExpressionFactory { IExpression condition(IExpression test, IExpression ifTrue, IExpression ifFalse); /** - * Creates a top level expression that represents a full query. - * @param elementClass The element class of the queried material - * @param expr The query - * @param parameters The parameters of the query - * @return A top level query expression - */ - <T> IContextExpression<T> contextExpression(Class<T> elementClass, IExpression expr, Object... parameters); - - /** * Create an expression that yields the first element of the * <code>collection</code> for which the <code>lambda</code> yields <code>true</code>. * @param collection The collection providing the elements to test diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QL.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QL.java index 7d34a8b9c..d3f0a911b 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QL.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QL.java @@ -12,8 +12,6 @@ package org.eclipse.equinox.p2.ql; import java.util.Iterator; import org.eclipse.equinox.internal.p2.ql.QueryContext; -import org.eclipse.equinox.internal.p2.ql.expression.QLFactory; -import org.eclipse.equinox.internal.p2.ql.parser.QLParser; import org.eclipse.equinox.p2.query.IQueryable; /** @@ -21,22 +19,6 @@ import org.eclipse.equinox.p2.query.IQueryable; */ public abstract class QL { /** - * Returns the default expression factory. - * @return the default expression factory. - */ - public static IQLFactory getFactory() { - return QLFactory.INSTANCE; - } - - /** - * Creates a new instance of the default expression parser. - * @return the new parser. - */ - public static IQLParser newParser() { - return new QLParser(getFactory()); - } - - /** * Creates a query context based on the given queryable * @param queryable The queryable to use for the creation of the context * @return A new context diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLContextQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLContextQuery.java index 97d89e135..b8733d63c 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLContextQuery.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLContextQuery.java @@ -12,22 +12,26 @@ package org.eclipse.equinox.p2.ql; import java.util.Iterator; import org.eclipse.equinox.internal.p2.ql.expression.QLUtil; +import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.index.IIndexProvider; +import org.eclipse.equinox.p2.metadata.index.IQueryWithIndex; import org.eclipse.equinox.p2.query.IQueryResult; /** * An IQuery 'context query' implementation that is based on the p2 query language. */ -public class QLContextQuery<T> extends QLQuery<T> { +public class QLContextQuery<T> extends QLQuery<T> implements IQueryWithIndex<T> { private final IContextExpression<T> expression; + private IIndexProvider indexProvider; /** * Creates a new query instance with indexed parameters. * @param expression The expression to use for the query. */ - public QLContextQuery(IContextExpression<T> expression) { - super(expression.getElementClass()); - this.expression = expression; + public QLContextQuery(Class<T> elementClass, org.eclipse.equinox.p2.metadata.expression.IContextExpression<T> expression) { + super(elementClass); + this.expression = (IContextExpression<T>) expression; } /** @@ -37,7 +41,14 @@ public class QLContextQuery<T> extends QLQuery<T> { * @param parameters Parameters to use for the query. */ public QLContextQuery(Class<T> elementClass, String expression, Object... parameters) { - this(QL.getFactory().contextExpression(elementClass, parser.parseQuery(expression), parameters)); + this(elementClass, ExpressionUtil.getFactory().<T> contextExpression(ExpressionUtil.getParser().parseQuery(expression), parameters)); + } + + public IQueryResult<T> perform(IIndexProvider<T> idxProvider) { + indexProvider = idxProvider; + + // TODO Fix so that we don't request everything here. + return new QueryResult<T>(evaluate(idxProvider.everything())); } public IQueryResult<T> perform(Iterator<T> iterator) { @@ -48,9 +59,10 @@ public class QLContextQuery<T> extends QLQuery<T> { IEvaluationContext ctx; if (QLUtil.needsTranslationSupport(expression)) { IQueryContext<T> queryContext = QL.newQueryContext(iterator); - ctx = expression.createContext(iterator, queryContext.getTranslationSupport(getLocale())); + ctx = expression.createContext(elementClass, iterator, queryContext.getTranslationSupport(getLocale())); } else - ctx = expression.createContext(iterator); + ctx = expression.createContext(elementClass, iterator); + ctx.setIndexProvider(indexProvider); Iterator<T> result = expression.iterator(ctx); return result; } @@ -65,9 +77,14 @@ public class QLContextQuery<T> extends QLQuery<T> { // IEvaluationContext ctx; if (QLUtil.needsTranslationSupport(expression)) - ctx = expression.createContext(queryContext.iterator(), queryContext.getTranslationSupport(getLocale())); + ctx = expression.createContext(elementClass, queryContext.iterator(), queryContext.getTranslationSupport(getLocale())); else - ctx = expression.createContext(queryContext.iterator()); + ctx = expression.createContext(elementClass, queryContext.iterator()); + ctx.setIndexProvider(indexProvider); return expression.evaluate(ctx); } + + public void setIndexProvider(IIndexProvider indexProvider) { + this.indexProvider = indexProvider; + } } diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLMatchQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLMatchQuery.java index 2e8adbf66..8cd491ab8 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLMatchQuery.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLMatchQuery.java @@ -43,7 +43,7 @@ public class QLMatchQuery<T> extends QLQuery<T> implements IMatchQuery<T> { * @param parameters Parameters to use for the query. */ public QLMatchQuery(Class<T> instanceClass, String expression, Object... parameters) { - this(instanceClass, QL.getFactory().<T> matchExpression(parser.parse(expression), parameters)); + this(instanceClass, ExpressionUtil.getFactory().<T> matchExpression(ExpressionUtil.getParser().parse(expression), parameters)); } /** diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLQuery.java index b8d48f64a..9987cdc7b 100644 --- a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLQuery.java +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/QLQuery.java @@ -17,7 +17,6 @@ import org.eclipse.equinox.p2.query.IQuery; * An IQuery 'context query' implementation that is based on the p2 query language. */ public abstract class QLQuery<T> implements IQuery<T> { - static final IQLParser parser = QL.newParser(); final Class<T> elementClass; private Locale locale; diff --git a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java index d07e03da0..d5c9ee1bb 100644 --- a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java +++ b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java @@ -327,7 +327,7 @@ public class ProfileSynchronizer { } // get all IUs from profile with marked property (existing) - IQueryResult<IInstallableUnit> dropinIUs = profile.query(new IUProfilePropertyQuery(PROP_FROM_DROPINS, Boolean.toString(true)), null); + IQueryResult<IInstallableUnit> dropinIUs = profile.query(new IUProfilePropertyQuery(PROP_FROM_DROPINS, Boolean.TRUE.toString()), null); Set<IInstallableUnit> all = allIUs.unmodifiableSet(); for (Iterator<IInstallableUnit> iter = dropinIUs.iterator(); iter.hasNext();) { IInstallableUnit iu = iter.next(); diff --git a/bundles/org.eclipse.equinox.p2.repository.tools/src_ant/org/eclipse/equinox/p2/internal/repository/tools/tasks/IUDescription.java b/bundles/org.eclipse.equinox.p2.repository.tools/src_ant/org/eclipse/equinox/p2/internal/repository/tools/tasks/IUDescription.java index f02a2b74a..d38685e70 100644 --- a/bundles/org.eclipse.equinox.p2.repository.tools/src_ant/org/eclipse/equinox/p2/internal/repository/tools/tasks/IUDescription.java +++ b/bundles/org.eclipse.equinox.p2.repository.tools/src_ant/org/eclipse/equinox/p2/internal/repository/tools/tasks/IUDescription.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.equinox.p2.internal.repository.tools.tasks; -import org.eclipse.equinox.p2.metadata.Version; - import java.util.*; import org.apache.tools.ant.types.DataType; import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; @@ -19,6 +17,7 @@ import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.internal.p2.metadata.query.LatestIUVersionQuery; import org.eclipse.equinox.p2.internal.repository.tools.Activator; import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.PipedQuery; @@ -112,8 +111,7 @@ public class IUDescription extends DataType { if (id != null) { if (version == null || version.length() == 0) { // Get the latest version of the iu - queries.add(new InstallableUnitQuery(id)); - queries.add(new LatestIUVersionQuery<IInstallableUnit>()); + queries.add(new LatestIUVersionQuery<IInstallableUnit>(new InstallableUnitQuery(id))); } else { Version iuVersion = Version.parseVersion(version); queries.add(new InstallableUnitQuery(id, iuVersion)); @@ -146,6 +144,8 @@ public class IUDescription extends DataType { String value = attributes.get(QUERY_VALUE); if (name == null) return null; + if (value == null) + value = IUPropertyQuery.ANY; return new IUPropertyQuery(name, value); } diff --git a/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF index 42f94454b..06554245a 100644 --- a/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF @@ -27,6 +27,7 @@ Import-Package: javax.xml.parsers, org.eclipse.equinox.p2.core, org.eclipse.equinox.p2.core.spi, org.eclipse.equinox.p2.metadata, + org.eclipse.equinox.p2.metadata.expression, org.eclipse.equinox.p2.metadata.query, org.eclipse.equinox.p2.query, org.eclipse.equinox.security.storage, diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/ArtifactKeyQuery.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/ArtifactKeyQuery.java index 0d48ccabf..4470a2499 100644 --- a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/ArtifactKeyQuery.java +++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/ArtifactKeyQuery.java @@ -11,22 +11,35 @@ package org.eclipse.equinox.p2.repository.artifact; -import org.eclipse.equinox.p2.metadata.VersionRange; - import org.eclipse.equinox.p2.metadata.IArtifactKey; -import org.eclipse.equinox.p2.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.VersionRange; +import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.query.ExpressionQuery; /** * An IArtifactQuery returning matching IArtifactKey objects. * @since 2.0 */ -public class ArtifactKeyQuery extends MatchQuery<IArtifactKey> { - public static final ArtifactKeyQuery ALL_KEYS = new ArtifactKeyQuery(); +public class ArtifactKeyQuery extends ExpressionQuery<IArtifactKey> { + private static IMatchExpression<IArtifactKey> MATCH_ALL_KEYS = ExpressionUtil.getFactory().matchExpression(ExpressionUtil.TRUE_EXPRESSION); + private static final IExpression matchKey = ExpressionUtil.parse("this == $0"); //$NON-NLS-1$ + private static final IExpression matchID = ExpressionUtil.parse("id == $0"); //$NON-NLS-1$ + private static final IExpression matchIDClassifierRange = ExpressionUtil.parse("id == $0 && version ~= $2 && (null == $1 || classifier == $1)"); //$NON-NLS-1$ + + private static IMatchExpression<IArtifactKey> createMatchExpression(IArtifactKey key) { + return key == null ? MATCH_ALL_KEYS : ExpressionUtil.getFactory().<IArtifactKey> matchExpression(matchKey, key); + } - private String id; - private String classifier; - private VersionRange range; - private IArtifactKey artifactKey; + private static IMatchExpression<IArtifactKey> createMatchExpression(String classifier, String id, VersionRange range) { + if (range == null) { + if (classifier == null) + return id == null ? MATCH_ALL_KEYS : ExpressionUtil.getFactory().<IArtifactKey> matchExpression(matchID, id); + range = VersionRange.emptyRange; + } + return ExpressionUtil.getFactory().<IArtifactKey> matchExpression(matchIDClassifierRange, id, classifier, range); + } + + public static final ArtifactKeyQuery ALL_KEYS = new ArtifactKeyQuery(); /** * Pass the id and/or version range to match IArtifactKeys against. @@ -36,46 +49,14 @@ public class ArtifactKeyQuery extends MatchQuery<IArtifactKey> { * @param range A version range, or <code>null</code> */ public ArtifactKeyQuery(String classifier, String id, VersionRange range) { - this.id = id; - this.classifier = classifier; - this.range = range; + super(IArtifactKey.class, createMatchExpression(classifier, id, range)); } public ArtifactKeyQuery() { - //matches everything + super(IArtifactKey.class, MATCH_ALL_KEYS); } public ArtifactKeyQuery(IArtifactKey key) { - this.artifactKey = key; - } - - public boolean isMatch(IArtifactKey key) { - if (artifactKey != null) - return matchKey(key); - - if (classifier != null && !key.getClassifier().equals(classifier)) - return false; - - if (id != null && !key.getId().equals(id)) - return false; - - if (range != null && !range.isIncluded(key.getVersion())) - return false; - - return true; - } - - protected boolean matchKey(IArtifactKey candidate) { - return artifactKey.equals(candidate); - } - - // We are interested in IArtifactKey objects - public Boolean getExcludeArtifactKeys() { - return Boolean.FALSE; - } - - // We are not interested in IArtifactDescriptor objects - public Boolean getExcludeArtifactDescriptors() { - return Boolean.TRUE; + super(IArtifactKey.class, createMatchExpression(key)); } } diff --git a/bundles/org.eclipse.equinox.p2.tests.ui/All p2 UI tests.launch b/bundles/org.eclipse.equinox.p2.tests.ui/All p2 UI tests.launch index 2bd7dd67b..0d7edbbce 100644 --- a/bundles/org.eclipse.equinox.p2.tests.ui/All p2 UI tests.launch +++ b/bundles/org.eclipse.equinox.p2.tests.ui/All p2 UI tests.launch @@ -61,10 +61,11 @@ <stringAttribute key="pde.version" value="3.3"/> <stringAttribute key="product" value="org.eclipse.sdk.ide"/> <booleanAttribute key="run_in_ui_thread" value="true"/> -<stringAttribute key="selected_target_plugins" value="org.eclipse.jdt.junit.core@default:default,org.eclipse.help.base@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.jdt.doc.user@default:default,org.eclipse.equinox.http.jetty@default:default,org.eclipse.jdt.junit.runtime@default:default,org.apache.commons.httpclient@default:default,org.apache.commons.logging@default:default,com.jcraft.jsch@default:default,org.junit*3.8.2.v20090203-1005@default:default,org.apache.ant@default:default,org.junit*4.8.1.v4_8_1_v20100114-1600@default:default,org.eclipse.jdt.apt.ui@default:default,org.eclipse.cvs@default:default,org.eclipse.text@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.equinox.concurrent@default:default,org.eclipse.core.commands@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.compare.core@default:default,org.eclipse.equinox.app@default:default,org.eclipse.ui.intro.universal@default:default,org.eclipse.pde.build@default:default,org.eclipse.update.configurator@3:true,org.sat4j.pb@default:default,org.eclipse.pde@default:default,org.eclipse.rcp@default:default,org.eclipse.help@default:default,org.objectweb.asm@default:default,org.eclipse.core.filesystem@default:default,org.eclipse.ui.views@default:default,org.eclipse.help.webapp@default:default,org.eclipse.core.jobs@default:default,org.apache.lucene@default:default,org.eclipse.ui.externaltools@default:default,org.eclipse.pde.api.tools@default:default,org.eclipse.core.runtime.compatibility.registry@default:false,org.eclipse.equinox.jsp.jasper@default:default,org.eclipse.core.runtime@default:true,org.eclipse.pde.ds.ui@default:default,org.eclipse.equinox.security.ui@default:default,org.eclipse.core.resources@default:default,org.eclipse.debug.core@default:default,org.eclipse.equinox.common@2:true,org.eclipse.platform@default:default,org.eclipse.equinox.http.registry@default:default,org.eclipse.jdt@default:default,org.junit4@default:default,org.eclipse.ui.net@default:default,org.eclipse.core.externaltools@default:default,org.eclipse.jdt.doc.isv@default:default,org.eclipse.core.variables@default:default,org.eclipse.jdt.junit4.runtime@default:default,org.eclipse.jdt.ui@default:default,org.eclipse.pde.core@default:default,org.eclipse.jsch.ui@default:default,org.eclipse.jdt.debug@default:default,org.eclipse.pde.ua.core@default:default,org.eclipse.ecf.ssl@default:false,org.eclipse.pde.ds.core@default:default,org.eclipse.ecf.provider.filetransfer@default:default,org.eclipse.team.ui@default:default,org.eclipse.search@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.pde.doc.user@default:default,org.eclipse.ecf.provider.filetransfer.httpclient@default:default,org.eclipse.jdt.core@default:default,org.eclipse.equinox.launcher.gtk.linux.x86_64@default:false,org.eclipse.equinox.security@default:default,org.eclipse.core.filebuffers@default:default,org.eclipse.jdt.launching@default:default,org.eclipse.jdt.debug.ui@default:default,org.eclipse.ui.workbench.compatibility@default:false,org.eclipse.ui.navigator.resources@default:default,org.eclipse.swt.gtk.linux.x86_64@default:false,org.eclipse.pde.junit.runtime@default:default,org.eclipse.ui.presentations.r21@default:default,org.eclipse.ui.ide@default:default,org.eclipse.ecf@default:default,org.eclipse.team.cvs.core@default:default,org.eclipse.ui.navigator@default:default,org.eclipse.ui.workbench.texteditor@default:default,javax.servlet.jsp@default:default,org.eclipse.jdt.core.manipulation@default:default,org.eclipse.equinox.jsp.jasper.registry@default:default,org.apache.commons.codec@default:default,org.mortbay.jetty.util@default:default,org.eclipse.core.runtime.compatibility.auth@default:default,org.eclipse.pde.api.tools.ui@default:default,org.eclipse.ui.intro@default:default,org.eclipse.jdt.apt.pluggable.core@default:default,org.apache.commons.el@default:default,org.eclipse.swt@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.sdk@default:default,org.eclipse.pde.runtime@default:default,com.ibm.icu@default:default,org.eclipse.core.runtime.compatibility@default:default,org.eclipse.update.core@default:default,org.eclipse.pde.ui.templates@default:default,org.eclipse.ui.views.log@default:default,org.eclipse.core.boot@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.pde.ui@default:default,org.eclipse.core.databinding.beans@default:default,org.eclipse.jdt.junit@default:default,org.eclipse.ui.views.properties.tabbed@default:default,org.eclipse.osgi@-1:true,org.eclipse.ecf.provider.filetransfer.httpclient.ssl@default:false,org.eclipse.ant.ui@default:default,org.eclipse.ui.ide.application@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.update.ui@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.update.scheduler@default:default,org.eclipse.help.appserver@default:default,org.eclipse.core.expressions@default:default,org.eclipse.ant.core@default:default,org.eclipse.debug.ui@default:default,org.eclipse.core.net.linux.x86_64@default:false,org.eclipse.ui.browser@default:default,org.apache.jasper@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.team.cvs.ui@default:default,org.eclipse.core.net@default:default,org.eclipse.ui.editors@default:default,org.eclipse.jdt.compiler.apt@default:false,org.eclipse.jdt.compiler.tool@default:false,org.eclipse.ui@default:default,org.eclipse.compare@default:default,org.eclipse.ui.cheatsheets@default:default,org.eclipse.pde.launching@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.http.servlet@default:default,org.eclipse.ltk.ui.refactoring@default:default,org.eclipse.jface.text@default:default,org.eclipse.ltk.core.refactoring@default:default,org.eclipse.team.cvs.ssh2@default:default,org.eclipse.equinox.util@default:default,org.eclipse.ant.launching@default:default,org.eclipse.jdt.apt.core@default:default,org.sat4j.core@default:default,org.eclipse.equinox.event@default:default,org.eclipse.ui.console@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.team.core@default:default,org.eclipse.ui.forms@default:default,org.eclipse.jface@default:default,org.eclipse.help.ui@default:default,org.eclipse.core.filesystem.linux.x86_64@default:false,org.mortbay.jetty.server@default:default,org.eclipse.osgi.services@default:default,javax.servlet@default:default,org.eclipse.pde.ua.ui@default:default,org.apache.lucene.analysis@default:default,org.eclipse.core.databinding@default:default,org.eclipse.osgi.util@default:default,org.eclipse.jsch.core@default:default,org.hamcrest.core@default:default,org.eclipse.ecf.provider.filetransfer.ssl@default:false"/> -<stringAttribute key="selected_workspace_plugins" value="org.eclipse.equinox.p2.garbagecollector@default:default,org.eclipse.equinox.simpleconfigurator.manipulator@default:default,org.eclipse.equinox.p2.console@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.p2.director.app@default:default,org.eclipse.equinox.p2.artifact.optimizers@default:default,org.eclipse.equinox.p2.repository.tools@default:default,org.eclipse.equinox.p2.tests.verifier@default:default,org.eclipse.equinox.p2.extensionlocation@default:default,org.eclipse.test.performance@default:default,org.eclipse.equinox.p2.ql@default:default,org.eclipse.equinox.p2.ui.sdk.scheduler@default:default,org.eclipse.equinox.p2.tests@default:default,org.eclipse.core.tests.harness@default:default,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:default,org.eclipse.equinox.p2.operations@default:default,org.eclipse.equinox.p2.reconciler.dropins@default:default,org.eclipse.equinox.p2.tests.ui@default:default,org.sat4j.pb@default:default,org.eclipse.equinox.p2.updatesite@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.simpleconfigurator@1:true,ie.wombat.jbdiff@default:default,org.eclipse.equinox.p2.touchpoint.natives@default:default,org.sat4j.core@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.frameworkadmin.test@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.p2.publisher@default:default,org.eclipse.equinox.p2.jarprocessor@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.exemplarysetup@default:default,org.eclipse.equinox.p2.touchpoint.eclipse@default:default,org.eclipse.equinox.p2.artifact.processors@default:default,org.eclipse.equinox.p2.installer@default:default,org.eclipse.equinox.p2.updatechecker@default:default,org.eclipse.equinox.p2.director@default:default,org.eclipse.equinox.p2.directorywatcher@default:default,org.eclipse.equinox.p2.ui@default:default,org.easymock@default:default,org.eclipse.equinox.p2.sar@default:default,ie.wombat.jbdiff.test@default:default,org.eclipse.equinox.p2.ui.sdk@default:default"/> +<stringAttribute key="selected_target_plugins" value="org.eclipse.ui.workbench.compatibility@default:false,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.concurrent@default:default,org.eclipse.team.cvs.ssh2@default:default,org.eclipse.equinox.common@2:true,org.eclipse.update.scheduler@default:default,org.eclipse.ui.externaltools@default:default,org.eclipse.ltk.core.refactoring@default:default,org.eclipse.pde@default:default,org.eclipse.jdt.junit.runtime@default:default,org.eclipse.ui.presentations.r21@default:default,org.eclipse.help.ui@default:default,org.eclipse.compare.core@default:default,org.eclipse.ecf@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.ide.application@default:default,org.eclipse.swt.gtk.linux.x86_64@default:false,org.eclipse.core.boot@default:default,org.eclipse.equinox.security.ui@default:default,org.eclipse.core.variables@default:default,org.eclipse.osgi.util@default:default,org.eclipse.equinox.jsp.jasper.registry@default:default,org.eclipse.core.runtime@default:true,org.eclipse.core.externaltools@default:default,org.eclipse.equinox.launcher.gtk.linux.x86_64@default:false,org.eclipse.jdt.apt.pluggable.core@default:default,org.eclipse.debug.core@default:default,org.eclipse.jdt.compiler.apt@default:false,org.eclipse.pde.ua.ui@default:default,org.eclipse.update.core@default:default,org.eclipse.sdk@default:default,org.eclipse.ant.core@default:default,org.eclipse.jdt.junit@default:default,org.eclipse.update.configurator@3:true,org.eclipse.pde.api.tools@default:default,org.eclipse.pde.ds.core@default:default,org.eclipse.pde.junit.runtime@default:default,org.eclipse.rcp@default:default,org.apache.commons.codec@default:default,org.eclipse.pde.ui.templates@default:default,org.eclipse.jdt.doc.user@default:default,javax.servlet@default:default,org.mortbay.jetty.util@default:default,org.eclipse.osgi.services@default:default,org.eclipse.ecf.provider.filetransfer.httpclient@default:default,org.mortbay.jetty.server@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.ltk.ui.refactoring@default:default,org.eclipse.team.cvs.ui@default:default,org.eclipse.ecf.ssl@default:false,org.eclipse.ecf.provider.filetransfer@default:default,org.eclipse.platform@default:default,org.eclipse.help.appserver@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.core.expressions@default:default,org.eclipse.help@default:default,org.eclipse.swt@default:default,org.eclipse.jdt.launching@default:default,org.eclipse.jdt.core@default:default,org.eclipse.core.resources@default:default,org.eclipse.text@default:default,org.junit*3.8.2.v20090203-1005@default:default,org.eclipse.jface@default:default,org.eclipse.equinox.app@default:default,org.eclipse.team.core@default:default,org.eclipse.pde.ui@default:default,org.eclipse.ant.ui@default:default,org.eclipse.core.filebuffers@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.cvs@default:default,org.eclipse.ui.forms@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.jdt.apt.ui@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.core.net@default:default,org.eclipse.core.jobs@default:default,org.eclipse.ecf.provider.filetransfer.ssl@default:false,javax.servlet.jsp@default:default,org.eclipse.pde.launching@default:default,org.eclipse.pde.api.tools.ui@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.jdt.doc.isv@default:default,org.eclipse.update.ui@default:default,org.eclipse.jdt@default:default,org.eclipse.pde.runtime@default:default,org.sat4j.pb@default:default,org.objectweb.asm@default:default,org.eclipse.jdt.junit.core@default:default,org.apache.commons.httpclient@default:default,org.eclipse.ui.console@default:default,org.eclipse.core.databinding@default:default,org.eclipse.ui.intro.universal@default:default,org.eclipse.core.contenttype@default:default,org.sat4j.core@default:default,org.apache.lucene.analysis@default:default,org.junit4@default:default,org.eclipse.ui.net@default:default,org.eclipse.ecf.provider.filetransfer.httpclient.ssl@default:false,org.eclipse.pde.ua.core@default:default,org.eclipse.ui.navigator.resources@default:default,org.eclipse.pde.doc.user@default:default,org.eclipse.jdt.compiler.tool@default:false,org.eclipse.ui.views.properties.tabbed@default:default,org.eclipse.pde.ds.ui@default:default,org.eclipse.ant.launching@default:default,com.jcraft.jsch@default:default,org.eclipse.team.ui@default:default,org.hamcrest.core@default:default,org.eclipse.help.base@default:default,org.eclipse.jsch.core@default:default,org.eclipse.equinox.jsp.jasper@default:default,org.eclipse.core.runtime.compatibility.auth@default:default,org.eclipse.core.databinding.beans@default:default,org.eclipse.jdt.ui@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.equinox.event@default:default,org.eclipse.help.webapp@default:default,org.apache.commons.logging@default:default,org.eclipse.ui.cheatsheets@default:default,org.apache.lucene@default:default,org.eclipse.pde.core@default:default,org.eclipse.ui.ide@default:default,org.eclipse.core.runtime.compatibility@default:default,org.apache.jasper@default:default,org.eclipse.core.commands@default:default,org.eclipse.jdt.debug@default:default,org.eclipse.osgi@-1:true,org.eclipse.equinox.http.jetty@default:default,org.eclipse.ui.views.log@default:default,org.eclipse.ui.editors@default:default,org.eclipse.core.filesystem.linux.x86_64@default:false,org.eclipse.jface.text@default:default,org.eclipse.ui.workbench.texteditor@default:default,org.eclipse.ui.browser@default:default,org.eclipse.pde.build@default:default,org.eclipse.jdt.junit4.runtime@default:default,org.apache.commons.el@default:default,org.eclipse.ui.intro@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.compare@default:default,org.eclipse.jdt.core.manipulation@default:default,org.eclipse.equinox.http.registry@default:default,org.apache.ant@default:default,org.eclipse.ui.navigator@default:default,org.eclipse.team.cvs.core@default:default,org.junit*4.8.1.v4_8_1_v20100114-1600@default:default,org.eclipse.debug.ui@default:default,org.eclipse.jdt.apt.core@default:default,org.eclipse.equinox.security@default:default,com.ibm.icu@default:default,org.eclipse.core.filesystem@default:default,org.eclipse.search@default:default,org.eclipse.jsch.ui@default:default,org.eclipse.ui@default:default,org.eclipse.core.net.linux.x86_64@default:false,org.eclipse.core.runtime.compatibility.registry@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.http.servlet@default:default,org.eclipse.jdt.debug.ui@default:default"/> +<stringAttribute key="selected_workspace_plugins" value="org.sat4j.core@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.exemplarysetup@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.updatechecker@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.touchpoint.natives@default:default,org.eclipse.equinox.p2.ui.sdk.scheduler@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.artifact.processors@default:default,org.eclipse.equinox.p2.publisher@default:default,org.sat4j.pb@default:default,org.eclipse.equinox.p2.director@default:default,org.eclipse.equinox.simpleconfigurator.manipulator@default:default,org.eclipse.equinox.p2.updatesite@default:default,org.eclipse.equinox.p2.ui.sdk@default:default,org.eclipse.equinox.p2.garbagecollector@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,ie.wombat.jbdiff.test@default:default,org.eclipse.equinox.p2.tests.verifier@default:default,org.eclipse.test.performance@default:default,org.eclipse.equinox.simpleconfigurator@1:true,org.eclipse.equinox.p2.jarprocessor@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:default,org.eclipse.equinox.p2.extensionlocation@default:default,org.eclipse.equinox.p2.console@default:default,org.eclipse.equinox.p2.ql@default:default,org.eclipse.equinox.p2.reconciler.dropins@default:default,org.eclipse.equinox.p2.artifact.optimizers@default:default,ie.wombat.jbdiff@default:default,org.eclipse.equinox.p2.sar@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.p2.ui@default:default,org.eclipse.equinox.p2.tests.ui@default:default,org.eclipse.equinox.frameworkadmin.test@default:default,org.eclipse.equinox.p2.repository.tools@default:default,org.eclipse.equinox.p2.directorywatcher@default:default,org.eclipse.equinox.p2.director.app@default:default,org.eclipse.core.tests.harness@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.p2.operations@default:default,org.eclipse.equinox.p2.touchpoint.eclipse@default:default,org.eclipse.equinox.p2.tests@default:default,org.eclipse.equinox.p2.installer@default:default,org.easymock@default:default"/> <booleanAttribute key="show_selected_only" value="false"/> <booleanAttribute key="tracing" value="false"/> +<booleanAttribute key="useCustomFeatures" value="false"/> <booleanAttribute key="useDefaultConfig" value="true"/> <booleanAttribute key="useDefaultConfigArea" value="false"/> <booleanAttribute key="useProduct" value="false"/> diff --git a/bundles/org.eclipse.equinox.p2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/query/QueryableMetadataRepositoryManagerTest.java b/bundles/org.eclipse.equinox.p2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/query/QueryableMetadataRepositoryManagerTest.java index 1dcda22d3..ceb273c84 100644 --- a/bundles/org.eclipse.equinox.p2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/query/QueryableMetadataRepositoryManagerTest.java +++ b/bundles/org.eclipse.equinox.p2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/query/QueryableMetadataRepositoryManagerTest.java @@ -193,7 +193,7 @@ public class QueryableMetadataRepositoryManagerTest extends AbstractQueryTest { // null IUPropertyQuery collects all IUs result = manager.query(new InstallableUnitQuery((String) null), getMonitor()); int iuCount = queryResultSize(result); - result = manager.query(new IUPropertyQuery(null, null), getMonitor()); + result = manager.query(new IUPropertyQuery(null, IUPropertyQuery.ANY), getMonitor()); assertEquals("2.2", iuCount, queryResultSize(result)); } diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java index f54645f55..a4e2084c7 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java @@ -474,7 +474,7 @@ public class CompositeMetadataRepositoryTest extends AbstractProvisioningTest { CompositeMetadataRepository compositeRepo = createRepo(false); compositeRepo.addChild(location1); compositeRepo.addChild(location2); - PipedQuery cQuery = new PipedQuery(new MatchQuery() { + IQuery cQuery = new LatestIUVersionQuery(new MatchQuery() { public boolean isMatch(Object candidate) { if (candidate instanceof IInstallableUnit) { IInstallableUnit iInstallableUnit = (IInstallableUnit) candidate; @@ -483,7 +483,7 @@ public class CompositeMetadataRepositoryTest extends AbstractProvisioningTest { } return false; } - }, new LatestIUVersionQuery()); + }); IQueryResult queryResult = compositeRepo.query(cQuery, monitor); assertEquals("1.0", 1, queryResultSize(queryResult)); assertEquals("1.1", Version.createOSGi(2, 2, 0), ((IInstallableUnit) queryResult.iterator().next()).getVersion()); diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/AddIUProperty.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/AddIUProperty.java index 9453e95be..faac57f10 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/AddIUProperty.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/AddIUProperty.java @@ -89,7 +89,7 @@ public class AddIUProperty extends AbstractProvisioningTest { allProfileIUs = profile.query(InstallableUnitQuery.ANY, null); assertEquals(queryResultSize(allProfileIUs), 1); - IQueryResult iuProfileProperties = profile.query(new IUProfilePropertyQuery(SimplePlanner.INCLUSION_RULES, null), null); + IQueryResult iuProfileProperties = profile.query(new IUProfilePropertyQuery(SimplePlanner.INCLUSION_RULES, IUProfilePropertyQuery.ANY), null); assertEquals(queryResultSize(iuProfileProperties), 1); //Remove a1 optionality - should be a no-op diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUProperties.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUProperties.java index 8482dc581..0a872dd8c 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUProperties.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUProperties.java @@ -8,10 +8,9 @@ ******************************************************************************/ package org.eclipse.equinox.p2.tests.planner; -import org.eclipse.equinox.internal.p2.engine.ProvisioningPlan; - import org.eclipse.core.runtime.IStatus; import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.internal.p2.engine.ProvisioningPlan; import org.eclipse.equinox.internal.provisional.p2.director.ProfileChangeRequest; import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; @@ -59,7 +58,7 @@ public class IUProperties extends AbstractProvisioningTest { IStatus s = engine.perform(pp1, null); if (!s.isOK()) LogHelper.log(s); - IQueryResult queryResult = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", null), null); + IQueryResult queryResult = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", IUProfilePropertyQuery.ANY), null); assertEquals(1, queryResultSize(queryResult)); ProfileChangeRequest req2 = new ProfileChangeRequest(profile); diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUPropertyRemoval.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUPropertyRemoval.java index 206e018e1..8badf906e 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUPropertyRemoval.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/IUPropertyRemoval.java @@ -8,9 +8,8 @@ ******************************************************************************/ package org.eclipse.equinox.p2.tests.planner; -import org.eclipse.equinox.internal.p2.engine.ProvisioningPlan; - import org.eclipse.core.runtime.IStatus; +import org.eclipse.equinox.internal.p2.engine.ProvisioningPlan; import org.eclipse.equinox.internal.provisional.p2.director.ProfileChangeRequest; import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; @@ -50,7 +49,7 @@ public class IUPropertyRemoval extends AbstractProvisioningTest { IProvisioningPlan pp1 = planner.getProvisioningPlan(req1, null, null); assertEquals(IStatus.OK, pp1.getStatus().getSeverity()); engine.perform(pp1, null); - IQueryResult res = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", null), null); + IQueryResult res = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", IUProfilePropertyQuery.ANY), null); assertEquals(2, queryResultSize(res)); ProfileChangeRequest req2 = new ProfileChangeRequest(profile); @@ -58,7 +57,7 @@ public class IUPropertyRemoval extends AbstractProvisioningTest { ProvisioningPlan pp2 = (ProvisioningPlan) planner.getProvisioningPlan(req2, null, null); assertEquals(1, pp2.getOperands().length); engine.perform(pp2, null); - IQueryResult res2 = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", null), null); + IQueryResult res2 = getProfile(profileId).query(new IUProfilePropertyQuery("FOO", IUProfilePropertyQuery.ANY), null); assertEquals(1, queryResultSize(res2)); } } diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/EvaluatorTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/EvaluatorTest.java index a46c4e426..137922078 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/EvaluatorTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/EvaluatorTest.java @@ -19,6 +19,7 @@ import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability; import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory; import org.eclipse.equinox.p2.metadata.*; import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.expression.IContextExpression; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; import org.eclipse.equinox.p2.publisher.PublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherResult; @@ -34,8 +35,8 @@ import org.eclipse.equinox.p2.tests.TestActivator; import org.osgi.framework.Filter; public class EvaluatorTest extends AbstractProvisioningTest { - private static final IQLParser parser = QL.newParser(); - private static final IQLFactory factory = QL.getFactory(); + private static final IExpressionParser parser = ExpressionUtil.getParser(); + private static final IExpressionFactory factory = ExpressionUtil.getFactory(); public void testArguments() throws Exception { IExpression expr = parser.parse("'a' == $0 && 'b' == $1 && 'c' == $2"); @@ -100,7 +101,7 @@ public class EvaluatorTest extends AbstractProvisioningTest { "parent.requiredCapabilities.unique(requirementsCache).select(rc | rc.filter == null || $2 ~= filter(rc.filter)), _, " + // "{rcs, child | rcs.exists(rc | child ~= rc)})}).limit(10)"; - IContextExpression expr = factory.contextExpression(IInstallableUnit.class, parser.parseQuery(exprString)); + IContextExpression expr = factory.contextExpression(parser.parseQuery(exprString)); System.out.println(expr.toString()); assertEquals(exprString, expr.toString()); } @@ -114,12 +115,12 @@ public class EvaluatorTest extends AbstractProvisioningTest { IExpression cmp2 = factory.equals(factory.at(factory.member(item, "properties"), factory.indexedParameter(1)), factory.indexedParameter(2)); IExpression lambda = factory.lambda(item, factory.and(cmp1, cmp2)); - IExpression latest = factory.latest(factory.select(factory.variable("everything"), lambda)); + IExpression latest = ((IQLFactory) factory).latest(((IQLFactory) factory).select(factory.variable("everything"), lambda)); // Create the query - IContextExpression e3 = factory.contextExpression(IInstallableUnit.class, latest, "test.bundle", "org.eclipse.equinox.p2.type.group", "true"); + IContextExpression<IInstallableUnit> e3 = factory.contextExpression(latest, "test.bundle", "org.eclipse.equinox.p2.type.group", "true"); IMetadataRepository repo = getMDR("/testData/metadataRepo/multipleversions1"); - IQueryResult result = repo.query(new QLContextQuery(e3), new NullProgressMonitor()); + IQueryResult result = repo.query(new QLContextQuery(IInstallableUnit.class, e3), new NullProgressMonitor()); assertEquals(queryResultSize(result), 1); } @@ -213,11 +214,11 @@ public class EvaluatorTest extends AbstractProvisioningTest { env.put("osgi.ws", "gtk"); env.put("osgi.arch", "x86"); - IContextExpression expr = factory.contextExpression(IInstallableUnit.class, parser.parseQuery("" + // + IContextExpression<IInstallableUnit> expr = factory.contextExpression(parser.parseQuery("" + // "select(x | x.id == $0 && x.version == $1).traverse(capabilityIndex(everything), _, { index, parent |" + // "index.satisfiesAny(parent.requiredCapabilities.select(rc | rc.filter == null || $2 ~= rc.filter))})"), "org.eclipse.sdk.feature.group", Version.create("3.5.0.v20090423-7Q7bA7DPR-wM38__Q4iRsmx9z0KOjbpx3AbyvXd-Uq7J2"), env); - QLContextQuery query = new QLContextQuery(expr); + QLContextQuery query = new QLContextQuery(IInstallableUnit.class, expr); IMetadataRepository repo = getMDR("/testData/galileoM7"); IQueryResult result = repo.query(query, new NullProgressMonitor()); assertEquals(queryResultSize(result), 411); @@ -235,7 +236,7 @@ public class EvaluatorTest extends AbstractProvisioningTest { env.put("osgi.ws", "gtk"); env.put("osgi.arch", "x86"); - IContextExpression expr = factory.contextExpression(IInstallableUnit.class, parser.parseQuery("" + // + IContextExpression<IInstallableUnit> expr = factory.contextExpression(parser.parseQuery("" + // "select(x | x.id == $0 && x.version == $1).traverse(parent |" + // "$5.satisfiesAny(parent.requiredCapabilities.select(rc | rc.filter == null || $4 ~= rc.filter))).intersect(" + // "select(x | x.id == $2 && x.version == $3).traverse(parent |" + // @@ -247,7 +248,7 @@ public class EvaluatorTest extends AbstractProvisioningTest { env,// index); - QLContextQuery query = new QLContextQuery(expr); + QLContextQuery query = new QLContextQuery(IInstallableUnit.class, expr); IQueryResult result = repo.query(query, new NullProgressMonitor()); assertEquals(queryResultSize(result), 184); } @@ -301,10 +302,10 @@ public class EvaluatorTest extends AbstractProvisioningTest { IExpression everything = factory.variable("everything"); IExpression lambda = factory.lambda(item, cmp1); - IContextExpression e3 = factory.contextExpression(Object.class, factory.select(everything, lambda)); + IContextExpression e3 = factory.contextExpression(((IQLFactory) factory).select(everything, lambda)); - IContextExpression<Object> contextExpression = factory.contextExpression(Object.class, parser.parseQuery(e3.toString()), "ian bull"); - QLContextQuery qlContextQuery = new QLContextQuery(contextExpression); + IContextExpression<Object> contextExpression = factory.contextExpression(parser.parseQuery(e3.toString()), "ian bull"); + QLContextQuery qlContextQuery = new QLContextQuery(IInstallableUnit.class, contextExpression); System.out.println(e3); IQueryResult queryResult = qlContextQuery.perform(items.iterator()); @@ -317,7 +318,7 @@ public class EvaluatorTest extends AbstractProvisioningTest { public void testMatchQueryInjectionInContext() throws Exception { IMetadataRepository repo = getMDR("/testData/galileoM7"); - IContextExpression expr = factory.contextExpression(IInstallableUnit.class, parser.parseQuery("select(x | iquery($0, x) || iquery($1, x)).latest()"), new MatchQuery() { + IContextExpression<IInstallableUnit> expr = factory.contextExpression(parser.parseQuery("select(x | iquery($0, x) || iquery($1, x)).latest()"), new MatchQuery() { @Override public boolean isMatch(Object candidate) { return "true".equals(((IInstallableUnit) candidate).getProperty("org.eclipse.equinox.p2.type.category")); @@ -328,7 +329,7 @@ public class EvaluatorTest extends AbstractProvisioningTest { return "true".equals(((IInstallableUnit) candidate).getProperty("org.eclipse.equinox.p2.type.group")); } }); - IQueryResult result = repo.query(new QLContextQuery(expr), new NullProgressMonitor()); + IQueryResult result = repo.query(new QLContextQuery(IInstallableUnit.class, expr), new NullProgressMonitor()); assertEquals(queryResultSize(result), 497); } diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/PerformanceTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/PerformanceTest.java index 972a701fb..174433938 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/PerformanceTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/PerformanceTest.java @@ -134,8 +134,7 @@ public class PerformanceTest extends AbstractProvisioningTest { IInstallableUnit[] roots = new IInstallableUnit[] {(IInstallableUnit) itor.next()}; IQuery query = new QLContextQuery(IInstallableUnit.class, "" + // - "$0.traverse(set(), capabilityIndex(everything), _, {rqCache, index, parent | " + // - "index.satisfiesAny(parent.requiredCapabilities.unique(rqCache).select(rc | rc.filter == null || $1 ~= rc.filter))})", roots, env); + "$0.traverse(set(), _, { cache, parent | parent.requiredCapabilities.unique(cache).select(rc | rc.filter == null || $1 ~= rc.filter).collect(rc | everything.select(iu | iu ~= rc)).flatten()})", roots, env); long sliceTime = 0; long traverseTime = 0; diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestIndexes.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestIndexes.java new file mode 100644 index 000000000..2fe2ebf99 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestIndexes.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2009 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 + *******************************************************************************/ +package org.eclipse.equinox.p2.tests.ql; + +import java.net.URI; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.ql.QLContextQuery; +import org.eclipse.equinox.p2.query.IQuery; +import org.eclipse.equinox.p2.query.IQueryResult; +import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; +import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; +import org.eclipse.equinox.p2.tests.AbstractProvisioningTest; + +public class TestIndexes extends AbstractProvisioningTest { + + public void testIdIndexSimple() throws Exception { + IMetadataRepository repo = getMDR("/testData/galileoM7"); + IQuery<IInstallableUnit> query = new QLContextQuery<IInstallableUnit>(IInstallableUnit.class, "select(x | x.id == $0)", "org.eclipse.sdk.feature.group"); + IQueryResult<IInstallableUnit> result = repo.query(query, getMonitor()); + assertEquals(queryResultSize(result), 1); + } + + public void testIdIndexWithOR() throws Exception { + IMetadataRepository repo = getMDR("/testData/galileoM7"); + IQuery<IInstallableUnit> query = new QLContextQuery<IInstallableUnit>(IInstallableUnit.class, "select(x | x.id == $0 || x.id == $1)", "org.eclipse.sdk.feature.group", "org.eclipse.sdk.feature.jar"); + IQueryResult<IInstallableUnit> result = repo.query(query, getMonitor()); + assertEquals(queryResultSize(result), 2); + } + + public void testIdIndexWithNot() throws Exception { + IMetadataRepository repo = getMDR("/testData/galileoM7"); + IQuery<IInstallableUnit> query = new QLContextQuery<IInstallableUnit>(IInstallableUnit.class, "select(x | x.id == $0 || x.id != $1)", "org.eclipse.sdk.feature.group", "org.eclipse.sdk.feature.jar"); + IQueryResult<IInstallableUnit> result = repo.query(query, getMonitor()); + assertEquals(queryResultSize(result), 3464); + } + + public void testCapabilityIndexSimple() throws Exception { + IMetadataRepository repo = getMDR("/testData/galileoM7"); + IQuery<IInstallableUnit> query = new QLContextQuery<IInstallableUnit>(IInstallableUnit.class, "select(x | x.providedCapabilities.exists(pc | pc.namespace == 'org.eclipse.equinox.p2.iu' && pc.name == $0))", "org.eclipse.core.resources"); + IQueryResult<IInstallableUnit> result = repo.query(query, getMonitor()); + assertEquals(queryResultSize(result), 1); + } + + public void testCapabilityIndexMatches() throws Exception { + IMetadataRepository repo = getMDR("/testData/galileoM7"); + IRequirement requirement = MetadataFactory.createRequiredCapability("org.eclipse.equinox.p2.iu", "org.eclipse.core.resources", null, null, 1, 2, true); + IQuery<IInstallableUnit> query = new QLContextQuery<IInstallableUnit>(IInstallableUnit.class, "select(x | x ~= $0)", requirement); + IQueryResult<IInstallableUnit> result = repo.query(query, getMonitor()); + assertEquals(queryResultSize(result), 1); + } + + private IMetadataRepository getMDR(String uri) throws Exception { + URI metadataRepo = getTestData("1.1", uri).toURI(); + + IMetadataRepositoryManager metadataManager = (IMetadataRepositoryManager) getAgent().getService(IMetadataRepositoryManager.SERVICE_NAME); + assertNotNull(metadataManager); + + return metadataManager.loadRepository(metadataRepo, new NullProgressMonitor()); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestQueryReimplementation.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestQueryReimplementation.java index 9a51eda88..6010bee0b 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestQueryReimplementation.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ql/TestQueryReimplementation.java @@ -12,9 +12,8 @@ package org.eclipse.equinox.p2.tests.ql; import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory; import org.eclipse.equinox.p2.metadata.*; -import org.eclipse.equinox.p2.metadata.expression.IExpression; -import org.eclipse.equinox.p2.metadata.expression.IExpressionParser; -import org.eclipse.equinox.p2.ql.*; +import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.ql.QLMatchQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.equinox.p2.tests.AbstractProvisioningTest; @@ -26,7 +25,7 @@ public class TestQueryReimplementation extends AbstractProvisioningTest { private static final IExpression expr2; static { - IQLParser parser = QL.newParser(); + IExpressionParser parser = ExpressionUtil.getParser(); // This expression is used in case the updateFrom is an IInstallableUnitPatch // @@ -41,15 +40,15 @@ public class TestQueryReimplementation extends AbstractProvisioningTest { } public UpdateQuery(IInstallableUnit updateFrom) { - super(IInstallableUnit.class, QL.getFactory().matchExpression(updateFrom instanceof IInstallableUnitPatch ? expr1 : expr2, updateFrom, IInstallableUnitPatch.class)); + super(IInstallableUnit.class, ExpressionUtil.getFactory().matchExpression(updateFrom instanceof IInstallableUnitPatch ? expr1 : expr2, updateFrom, IInstallableUnitPatch.class)); } } public static class IUPropertyQuery extends QLMatchQuery { - private static final IExpression expr = QL.newParser().parse("properties[$0] == $1"); + private static final IExpression expr = ExpressionUtil.getParser().parse("properties[$0] == $1"); public IUPropertyQuery(String propertyName, String propertyValue) { - super(IInstallableUnit.class, QL.getFactory().matchExpression(expr, propertyName, propertyValue)); + super(IInstallableUnit.class, ExpressionUtil.getFactory().matchExpression(expr, propertyName, propertyValue)); } } @@ -64,7 +63,7 @@ public class TestQueryReimplementation extends AbstractProvisioningTest { private static final IExpression idRangeQuery; static { - IExpressionParser parser = QL.newParser(); + IExpressionParser parser = ExpressionUtil.getParser(); idVersionQuery = parser.parse("($0 == null || $0 == id) && ($1 == null || $1 == version)"); idRangeQuery = parser.parse("($0 == null || $0 == id) && ($1 == null || version ~= $1)"); } @@ -87,7 +86,7 @@ public class TestQueryReimplementation extends AbstractProvisioningTest { * @param range The version range to match */ public InstallableUnitQuery(String id, VersionRange range) { - super(IInstallableUnit.class, QL.getFactory().matchExpression(idRangeQuery, id, range)); + super(IInstallableUnit.class, ExpressionUtil.getFactory().matchExpression(idRangeQuery, id, range)); } /** @@ -98,7 +97,7 @@ public class TestQueryReimplementation extends AbstractProvisioningTest { * @param version The precise version that a matching unit must have */ public InstallableUnitQuery(String id, Version version) { - super(IInstallableUnit.class, QL.getFactory().matchExpression(idVersionQuery, id, version)); + super(IInstallableUnit.class, ExpressionUtil.getFactory().matchExpression(idVersionQuery, id, version)); } /** diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java index c126460e7..b422333d7 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java +++ b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java @@ -14,13 +14,13 @@ import com.ibm.icu.util.Calendar; import com.ibm.icu.util.ULocale; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; -import org.eclipse.equinox.internal.p2.metadata.query.IUPropertyQuery; import org.eclipse.equinox.internal.provisional.p2.updatechecker.*; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.engine.IProfileRegistry; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.query.IQuery; +import org.eclipse.equinox.p2.query.MatchQuery; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.IStartup; import org.eclipse.ui.statushandlers.StatusManager; @@ -69,21 +69,15 @@ public class AutomaticUpdateScheduler implements IStartup { * this query to the automatic update checker and it will be referenced during * the life of the platform. */ - private class IUProfilePropertyByIdQuery extends IUPropertyQuery { + private class IUProfilePropertyByIdQuery extends MatchQuery<IInstallableUnit> { + private final String propertyName; private IProfile cachedProfile; /** * Creates a new query on the given property name and value. */ - public IUProfilePropertyByIdQuery(String propertyName, String propertyValue) { - super(propertyName, propertyValue); - } - - protected String getProperty(IInstallableUnit iu, String name) { - IProfile profile = getProfile(); - if (profile == null) - return null; - return profile.getInstallableUnitProperty(iu, name); + public IUProfilePropertyByIdQuery(String propertyName) { + this.propertyName = propertyName; } private IProfile getProfile() { @@ -100,6 +94,11 @@ public class AutomaticUpdateScheduler implements IStartup { public void postPerform() { cachedProfile = null; } + + public boolean isMatch(IInstallableUnit candidate) { + IProfile profile = getProfile(); + return profile != null && Boolean.valueOf(profile.getInstallableUnitProperty(candidate, propertyName)).booleanValue(); + } } /** @@ -171,7 +170,7 @@ public class AutomaticUpdateScheduler implements IStartup { private IQuery<IInstallableUnit> getProfileQuery() { // We specifically avoid using the default policy's root property so that we don't load all the // p2 UI classes in doing so. - return new IUProfilePropertyByIdQuery(IProfile.PROP_PROFILE_ROOT_IU, Boolean.toString(true)); + return new IUProfilePropertyByIdQuery(IProfile.PROP_PROFILE_ROOT_IU); } private int getDay(IPreferenceStore pref) { diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/QueryProvider.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/QueryProvider.java index adf89d3b3..8b5793947 100644 --- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/QueryProvider.java +++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/QueryProvider.java @@ -92,7 +92,7 @@ public class QueryProvider { if (context.getViewType() == IUViewQueryContext.AVAILABLE_VIEW_FLAT || !context.getUseCategories()) { AvailableIUWrapper wrapper = new AvailableIUWrapper(queryable, element, false, context.getShowAvailableChildren()); if (showLatest) - topLevelQuery = new PipedQuery<IInstallableUnit>(topLevelQuery, new LatestIUVersionQuery<IInstallableUnit>()); + topLevelQuery = new LatestIUVersionQuery<IInstallableUnit>(topLevelQuery); if (targetProfile != null) wrapper.markInstalledIUs(targetProfile, hideInstalled); return new ElementQueryDescriptor(queryable, topLevelQuery, new Collector<Object>(), wrapper); @@ -114,14 +114,14 @@ public class QueryProvider { // if it's a category, there is a special query. if (element instanceof CategoryElement) { if (showLatest) - memberOfCategoryQuery = new PipedQuery<IInstallableUnit>(memberOfCategoryQuery, new LatestIUVersionQuery<IInstallableUnit>()); + memberOfCategoryQuery = new LatestIUVersionQuery<IInstallableUnit>(memberOfCategoryQuery); return new ElementQueryDescriptor(queryable, memberOfCategoryQuery, new Collector<Object>(), availableIUWrapper); } // It is not a category, we want to traverse the requirements that are groups. @SuppressWarnings("unchecked") IQuery<IInstallableUnit> query = CompoundQuery.createCompoundQuery(new IQuery[] {topLevelQuery, new RequiredIUsQuery(((IIUElement) element).getIU())}, true); if (showLatest) - query = new PipedQuery<IInstallableUnit>(query, new LatestIUVersionQuery<IInstallableUnit>()); + query = new LatestIUVersionQuery<IInstallableUnit>(query); // If it's not a category, these are generic requirements and should be filtered by the visibility property (topLevelQuery) return new ElementQueryDescriptor(queryable, query, new Collector<Object>(), availableIUWrapper); } diff --git a/bundles/org.eclipse.equinox.p2.updatesite/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.updatesite/META-INF/MANIFEST.MF index bc52dc44f..d410b84cb 100644 --- a/bundles/org.eclipse.equinox.p2.updatesite/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.updatesite/META-INF/MANIFEST.MF @@ -20,6 +20,7 @@ Import-Package: javax.xml.parsers, org.eclipse.equinox.internal.provisional.p2.metadata, org.eclipse.equinox.p2.core, org.eclipse.equinox.p2.metadata, + org.eclipse.equinox.p2.metadata.expression, org.eclipse.equinox.p2.metadata.query, org.eclipse.equinox.p2.publisher, org.eclipse.equinox.p2.publisher.actions, diff --git a/bundles/org.eclipse.equinox.p2.updatesite/src/org/eclipse/equinox/internal/p2/updatesite/SiteXMLAction.java b/bundles/org.eclipse.equinox.p2.updatesite/src/org/eclipse/equinox/internal/p2/updatesite/SiteXMLAction.java index 886f5579d..ebd5b07c3 100644 --- a/bundles/org.eclipse.equinox.p2.updatesite/src/org/eclipse/equinox/internal/p2/updatesite/SiteXMLAction.java +++ b/bundles/org.eclipse.equinox.p2.updatesite/src/org/eclipse/equinox/internal/p2/updatesite/SiteXMLAction.java @@ -23,6 +23,8 @@ import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory; import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.expression.*; +import org.eclipse.equinox.p2.metadata.query.ExpressionQuery; import org.eclipse.equinox.p2.metadata.query.InstallableUnitQuery; import org.eclipse.equinox.p2.publisher.*; import org.eclipse.equinox.p2.publisher.eclipse.URLEntry; @@ -125,13 +127,15 @@ public class SiteXMLAction extends AbstractPublisherAction { return Status.OK_STATUS; } + private static final IExpression qualifierMatchExpr = ExpressionUtil.parse("id == $0 && version ~= $1"); //$NON-NLS-1$ + private IInstallableUnit getFeatureIU(SiteFeature feature, IPublisherInfo publisherInfo, IPublisherResult results) { String id = feature.getFeatureIdentifier() + ".feature.group"; //$NON-NLS-1$ String versionString = feature.getFeatureVersion(); Version version = versionString != null && versionString.length() > 0 ? Version.create(versionString) : Version.emptyVersion; IQuery<IInstallableUnit> query = null; if (version.equals(Version.emptyVersion)) { - query = new PipedQuery<IInstallableUnit>(new InstallableUnitQuery(id), new LatestIUVersionQuery<IInstallableUnit>()); + query = new LatestIUVersionQuery<IInstallableUnit>(new InstallableUnitQuery(id)); } else { String qualifier; try { @@ -140,18 +144,10 @@ public class SiteXMLAction extends AbstractPublisherAction { qualifier = null; } if (qualifier != null && qualifier.endsWith(QUALIFIER)) { - final String v = versionString.substring(0, versionString.indexOf(QUALIFIER)); - IQuery<IInstallableUnit> qualifierQuery = new InstallableUnitQuery(id) { - private String qualifierVersion = v.endsWith(".") ? v.substring(0, v.length() - 1) : v; //$NON-NLS-1$ - - public boolean isMatch(IInstallableUnit candidate) { - if (super.isMatch(candidate)) { - return candidate.getVersion().toString().startsWith(qualifierVersion); - } - return false; - } - }; - query = new PipedQuery<IInstallableUnit>(qualifierQuery, new LatestIUVersionQuery<IInstallableUnit>()); + String v = versionString.substring(0, versionString.indexOf(QUALIFIER)); + String qualifierVersion = v.endsWith(".") ? v.substring(0, v.length() - 1) : v; //$NON-NLS-1$ + IQuery<IInstallableUnit> qualifierQuery = new ExpressionQuery<IInstallableUnit>(IInstallableUnit.class, qualifierMatchExpr, id, SimplePattern.compile(qualifierVersion + '*')); + query = new LatestIUVersionQuery<IInstallableUnit>(qualifierQuery); } else { query = new LimitQuery<IInstallableUnit>(new InstallableUnitQuery(id, version), 1); } |