/******************************************************************************* * Copyright (c) 2008, 2011 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 java.io.File; import java.io.OutputStream; import java.net.URI; import java.util.*; import org.eclipse.core.runtime.*; 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.metadata.Version; import org.eclipse.equinox.p2.query.*; import org.eclipse.equinox.p2.repository.IRunnableWithProgress; 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<IArtifactDescriptor> descriptorsToAdd = new HashSet<IArtifactDescriptor>(); private Map<IArtifactKey, List<IArtifactDescriptor>> artifactMap = new HashMap<IArtifactKey, List<IArtifactDescriptor>>(); private Set<IArtifactDescriptor> descriptorsToRemove = new HashSet<IArtifactDescriptor>(); private Map<String, String> propertyChanges = new HashMap<String, String>(); protected CachingArtifactRepository(IArtifactRepository innerRepo) { this.innerRepo = innerRepo; } public void save() { innerRepo.executeBatch(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { savePropertyChanges(); saveAdditions(); saveRemovals(); } }, null); } void saveRemovals() { for (IArtifactDescriptor desc : descriptorsToRemove) innerRepo.removeDescriptor(desc); descriptorsToRemove.clear(); } void saveAdditions() { if (descriptorsToAdd.isEmpty()) return; innerRepo.addDescriptors(descriptorsToAdd.toArray(new IArtifactDescriptor[descriptorsToAdd.size()])); descriptorsToAdd.clear(); artifactMap.clear(); } void savePropertyChanges() { for (String key : propertyChanges.keySet()) { String value = propertyChanges.get(key); innerRepo.setProperty(key, value == NULL ? null : value); } propertyChanges.clear(); } private void mapDescriptor(IArtifactDescriptor descriptor) { IArtifactKey key = descriptor.getArtifactKey(); List<IArtifactDescriptor> descriptors = artifactMap.get(key); if (descriptors == null) { descriptors = new ArrayList<IArtifactDescriptor>(); artifactMap.put(key, descriptors); } descriptors.add(descriptor); } private void unmapDescriptor(IArtifactDescriptor descriptor) { IArtifactKey key = descriptor.getArtifactKey(); List<IArtifactDescriptor> descriptors = 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, IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, descriptors.length); for (int i = 0; i < descriptors.length; i++) { ((ArtifactDescriptor) descriptors[i]).setRepository(this); descriptorsToAdd.add(descriptors[i]); mapDescriptor(descriptors[i]); subMonitor.worked(1); } } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void addDescriptors(IArtifactDescriptor[] descriptors) { addDescriptors(descriptors, new NullProgressMonitor()); } public synchronized void addDescriptor(IArtifactDescriptor toAdd, IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, 1); ((ArtifactDescriptor) toAdd).setRepository(this); descriptorsToAdd.add(toAdd); mapDescriptor(toAdd); subMonitor.worked(1); } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void addDescriptor(IArtifactDescriptor toAdd) { addDescriptor(toAdd, new NullProgressMonitor()); } public synchronized IArtifactDescriptor[] getArtifactDescriptors(IArtifactKey key) { List<IArtifactDescriptor> result = artifactMap.get(key); if (result == null) return innerRepo.getArtifactDescriptors(key); result = new ArrayList<IArtifactDescriptor>(result); result.addAll(Arrays.asList(innerRepo.getArtifactDescriptors(key))); return 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 final void removeAll(IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, 1); IArtifactDescriptor[] toRemove = descriptorsToAdd.toArray(new IArtifactDescriptor[descriptorsToAdd.size()]); for (int i = 0; i < toRemove.length; i++) doRemoveArtifact(toRemove[i]); subMonitor.worked(1); } finally { if (monitor != null) monitor.done(); } } @Deprecated public synchronized void removeAll() { this.removeAll(new NullProgressMonitor()); } public synchronized void removeDescriptor(IArtifactDescriptor descriptor, IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, 1); doRemoveArtifact(descriptor); subMonitor.worked(1); } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void removeDescriptor(IArtifactDescriptor descriptor) { removeDescriptor(descriptor, new NullProgressMonitor()); } public synchronized void removeDescriptor(IArtifactKey key, IProgressMonitor monitor) { try { IArtifactDescriptor[] toRemove = getArtifactDescriptors(key); SubMonitor subMonitor = SubMonitor.convert(monitor, toRemove.length); for (int i = 0; i < toRemove.length; i++) { doRemoveArtifact(toRemove[i]); subMonitor.worked(1); } } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void removeDescriptor(IArtifactKey key) { this.removeDescriptor(key, new NullProgressMonitor()); } public synchronized void removeDescriptors(IArtifactDescriptor[] descriptors, IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, descriptors.length); for (IArtifactDescriptor descriptor : descriptors) { doRemoveArtifact(descriptor); subMonitor.worked(1); } } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void removeDescriptors(IArtifactDescriptor[] descriptors) { removeDescriptors(descriptors, new NullProgressMonitor()); } public synchronized void removeDescriptors(IArtifactKey[] keys, IProgressMonitor monitor) { try { SubMonitor subMonitor = SubMonitor.convert(monitor, keys.length); for (IArtifactKey key : keys) { removeDescriptor(key); subMonitor.worked(1); } } finally { if (monitor != null) monitor.done(); } } @Deprecated public final synchronized void removeDescriptors(IArtifactKey[] keys) { removeDescriptors(keys, new NullProgressMonitor()); } /** * 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<String, String> getProperties() { // TODO need to combine the local and inner properties return innerRepo.getProperties(); } public String getProperty(String key) { return innerRepo.getProperty(key); } public String getProvider() { return innerRepo.getProvider(); } public IProvisioningAgent getProvisioningAgent() { return innerRepo.getProvisioningAgent(); } public String getType() { return innerRepo.getType(); } public String getVersion() { return innerRepo.getVersion(); } public boolean isModifiable() { return innerRepo.isModifiable(); } public String setProperty(String key, String value, IProgressMonitor monitor) { try { String result = getProperties().get(key); propertyChanges.put(key, value == null ? NULL : value); return result; } finally { if (monitor != null) monitor.done(); } } public final String setProperty(String key, String value) { return setProperty(key, value, new NullProgressMonitor()); } @SuppressWarnings("rawtypes") 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 IArtifactKey createArtifactKey(String classifier, String id, Version version) { return innerRepo.createArtifactKey(classifier, id, version); } public IQueryable<IArtifactDescriptor> descriptorQueryable() { 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 CompoundIterator<IArtifactDescriptor>(descs.iterator())); } }; return QueryUtil.compoundQueryable(cached, innerRepo.descriptorQueryable()); } public IQueryResult<IArtifactKey> query(IQuery<IArtifactKey> query, IProgressMonitor monitor) { final Iterator<IArtifactKey> keyIterator = artifactMap.keySet().iterator(); IQueryable<IArtifactKey> cached = new IQueryable<IArtifactKey>() { public IQueryResult<IArtifactKey> query(IQuery<IArtifactKey> q, IProgressMonitor mon) { return q.perform(keyIterator); } }; IQueryable<IArtifactKey> compound = QueryUtil.compoundQueryable(cached, innerRepo); return compound.query(query, monitor); } public IStatus executeBatch(IRunnableWithProgress runnable, IProgressMonitor monitor) { try { runnable.run(monitor); } catch (OperationCanceledException oce) { return new Status(IStatus.CANCEL, Activator.ID, oce.getMessage(), oce); } catch (Exception e) { return new Status(IStatus.ERROR, Activator.ID, e.getMessage(), e); } return Status.OK_STATUS; } }