blob: d6cfab6e96abf4275d5dc9d756ca20ae2a6a1fb4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 Code 9 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:
* Code 9 - initial API and implementation
******************************************************************************/
package org.eclipse.equinox.internal.provisional.p2.directorywatcher;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import java.io.File;
import java.io.OutputStream;
import java.net.URI;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.*;
import org.eclipse.equinox.internal.provisional.spi.p2.artifact.repository.MappedCollectionIterator;
import org.eclipse.equinox.p2.metadata.query.IQuery;
import org.eclipse.equinox.p2.repository.artifact.*;
import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor;
public class CachingArtifactRepository implements IArtifactRepository, IFileArtifactRepository {
private static final String NULL = ""; //$NON-NLS-1$
private IArtifactRepository innerRepo;
private Set descriptorsToAdd = new HashSet();
private Map artifactMap = new HashMap();
private Set descriptorsToRemove = new HashSet();
private Map propertyChanges = new HashMap();
protected CachingArtifactRepository(IArtifactRepository innerRepo) {
this.innerRepo = innerRepo;
}
public void save() {
savePropertyChanges();
saveAdditions();
saveRemovals();
}
private void saveRemovals() {
for (Iterator i = descriptorsToRemove.iterator(); i.hasNext();)
innerRepo.removeDescriptor((IArtifactDescriptor) i.next());
descriptorsToRemove.clear();
}
private void saveAdditions() {
if (descriptorsToAdd.isEmpty())
return;
innerRepo.addDescriptors((IArtifactDescriptor[]) descriptorsToAdd.toArray(new IArtifactDescriptor[descriptorsToAdd.size()]));
descriptorsToAdd.clear();
artifactMap.clear();
}
private void savePropertyChanges() {
for (Iterator i = propertyChanges.keySet().iterator(); i.hasNext();) {
String key = (String) i.next();
String value = (String) propertyChanges.get(key);
innerRepo.setProperty(key, value == NULL ? null : value);
}
propertyChanges.clear();
}
private void mapDescriptor(IArtifactDescriptor descriptor) {
IArtifactKey key = descriptor.getArtifactKey();
Collection descriptors = (Collection) artifactMap.get(key);
if (descriptors == null) {
descriptors = new ArrayList();
artifactMap.put(key, descriptors);
}
descriptors.add(descriptor);
}
private void unmapDescriptor(IArtifactDescriptor descriptor) {
IArtifactKey key = descriptor.getArtifactKey();
Collection descriptors = (Collection) artifactMap.get(key);
if (descriptors == null) {
// we do not have the descriptor locally so remember it to be removed from
// the inner repo on save.
descriptorsToRemove.add(descriptor);
return;
}
descriptors.remove(descriptor);
if (descriptors.isEmpty())
artifactMap.remove(key);
}
public synchronized void addDescriptors(IArtifactDescriptor[] descriptors) {
for (int i = 0; i < descriptors.length; i++) {
((ArtifactDescriptor) descriptors[i]).setRepository(this);
descriptorsToAdd.add(descriptors[i]);
mapDescriptor(descriptors[i]);
}
}
public synchronized void addDescriptor(IArtifactDescriptor toAdd) {
((ArtifactDescriptor) toAdd).setRepository(this);
descriptorsToAdd.add(toAdd);
mapDescriptor(toAdd);
}
public synchronized IArtifactDescriptor[] getArtifactDescriptors(IArtifactKey key) {
Collection result = (Collection) artifactMap.get(key);
if (result == null)
return innerRepo.getArtifactDescriptors(key);
result.addAll(Arrays.asList(innerRepo.getArtifactDescriptors(key)));
return (IArtifactDescriptor[]) result.toArray(new IArtifactDescriptor[result.size()]);
}
public synchronized boolean contains(IArtifactDescriptor descriptor) {
return descriptorsToAdd.contains(descriptor) || innerRepo.contains(descriptor);
}
public synchronized boolean contains(IArtifactKey key) {
return artifactMap.containsKey(key) || innerRepo.contains(key);
}
public IStatus getArtifact(IArtifactDescriptor descriptor, OutputStream destination, IProgressMonitor monitor) {
return innerRepo.getArtifact(descriptor, destination, monitor);
}
public IStatus getRawArtifact(IArtifactDescriptor descriptor, OutputStream destination, IProgressMonitor monitor) {
return innerRepo.getRawArtifact(descriptor, destination, monitor);
}
public IStatus getArtifacts(IArtifactRequest[] requests, IProgressMonitor monitor) {
return Status.OK_STATUS;
}
public OutputStream getOutputStream(IArtifactDescriptor descriptor) {
return null;
}
public synchronized void removeAll() {
IArtifactDescriptor[] toRemove = (IArtifactDescriptor[]) descriptorsToAdd.toArray(new IArtifactDescriptor[descriptorsToAdd.size()]);
for (int i = 0; i < toRemove.length; i++)
doRemoveArtifact(toRemove[i]);
}
public synchronized void removeDescriptor(IArtifactDescriptor descriptor) {
doRemoveArtifact(descriptor);
}
public synchronized void removeDescriptor(IArtifactKey key) {
IArtifactDescriptor[] toRemove = getArtifactDescriptors(key);
for (int i = 0; i < toRemove.length; i++)
doRemoveArtifact(toRemove[i]);
}
/**
* Removes the given descriptor and returns <code>true</code> if and only if the
* descriptor existed in the repository, and was successfully removed.
*/
private boolean doRemoveArtifact(IArtifactDescriptor descriptor) {
// if the descriptor is already in the pending additoins, remove it
boolean result = descriptorsToAdd.remove(descriptor);
if (result)
unmapDescriptor(descriptor);
// either way, note this as a descriptor to remove from the inner repo
descriptorsToRemove.add(descriptor);
return result;
}
public String getDescription() {
return innerRepo.getDescription();
}
public URI getLocation() {
return innerRepo.getLocation();
}
public String getName() {
return innerRepo.getName();
}
public Map getProperties() {
// TODO need to combine the local and inner properties
return innerRepo.getProperties();
}
public String getProvider() {
return innerRepo.getProvider();
}
public String getType() {
return innerRepo.getType();
}
public String getVersion() {
return innerRepo.getVersion();
}
public boolean isModifiable() {
return innerRepo.isModifiable();
}
public void setDescription(String description) {
innerRepo.setDescription(description);
}
public void setName(String name) {
innerRepo.setName(name);
}
public String setProperty(String key, String value) {
String result = (String) getProperties().get(key);
propertyChanges.put(key, value == null ? NULL : value);
return result;
}
public void setProvider(String provider) {
innerRepo.setProvider(provider);
}
public Object getAdapter(Class adapter) {
return innerRepo.getAdapter(adapter);
}
public File getArtifactFile(IArtifactKey key) {
if (innerRepo instanceof IFileArtifactRepository)
return ((IFileArtifactRepository) innerRepo).getArtifactFile(key);
return null;
}
public File getArtifactFile(IArtifactDescriptor descriptor) {
if (innerRepo instanceof IFileArtifactRepository)
return ((IFileArtifactRepository) innerRepo).getArtifactFile(descriptor);
return null;
}
public IArtifactDescriptor createArtifactDescriptor(IArtifactKey key) {
return innerRepo.createArtifactDescriptor(key);
}
public synchronized Collector query(IQuery query, Collector collector, IProgressMonitor monitor) {
if (monitor != null && monitor.isCanceled())
return collector;
final boolean excludeKeys = Boolean.TRUE.equals(query.getProperty(IArtifactRepository.QUERY_EXCLUDE_KEYS));
final boolean excludeDescriptors = Boolean.TRUE.equals(query.getProperty(IArtifactRepository.QUERY_EXCLUDE_DESCRIPTORS));
if (excludeKeys && excludeDescriptors)
return collector;
IQueryable cached = new IQueryable() {
public Collector query(IQuery query, Collector collector, IProgressMonitor monitor) {
Iterator i = !excludeDescriptors ? new MappedCollectionIterator(artifactMap, !excludeKeys) : artifactMap.keySet().iterator();
return query.perform(i, collector);
}
};
CompoundQueryable compound = new CompoundQueryable(new IQueryable[] {cached, innerRepo});
return compound.query(query, collector, monitor);
}
}