blob: cafc760562d3b393a3b15ee5019cc805b1246828 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2017 Code 9 and others.
*
* This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License 2.0 which accompanies this distribution, and is
* available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Code 9 - initial API and implementation
* Red Hat Inc. - Fix compiler problems from generified IAdaptable#getAdapter
******************************************************************************/
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 IFileArtifactRepository {
private static final String NULL = ""; //$NON-NLS-1$
private IArtifactRepository innerRepo;
private Set<IArtifactDescriptor> descriptorsToAdd = new HashSet<>();
private Map<IArtifactKey, List<IArtifactDescriptor>> artifactMap = new HashMap<>();
private Set<IArtifactDescriptor> descriptorsToRemove = new HashSet<>();
private Map<String, String> propertyChanges = new HashMap<>();
protected CachingArtifactRepository(IArtifactRepository innerRepo) {
this.innerRepo = innerRepo;
}
public void save() {
innerRepo.executeBatch(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<>();
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);
}
@Override
public synchronized void addDescriptors(IArtifactDescriptor[] descriptors, IProgressMonitor monitor) {
try {
SubMonitor subMonitor = SubMonitor.convert(monitor, descriptors.length);
for (IArtifactDescriptor descriptor : descriptors) {
((ArtifactDescriptor) descriptor).setRepository(this);
descriptorsToAdd.add(descriptor);
mapDescriptor(descriptor);
subMonitor.worked(1);
}
} finally {
if (monitor != null)
monitor.done();
}
}
@Override
@Deprecated
public final synchronized void addDescriptors(IArtifactDescriptor[] descriptors) {
addDescriptors(descriptors, new NullProgressMonitor());
}
@Override
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();
}
}
@Override
@Deprecated
public final synchronized void addDescriptor(IArtifactDescriptor toAdd) {
addDescriptor(toAdd, new NullProgressMonitor());
}
@Override
public synchronized IArtifactDescriptor[] getArtifactDescriptors(IArtifactKey key) {
List<IArtifactDescriptor> result = artifactMap.get(key);
if (result == null)
return innerRepo.getArtifactDescriptors(key);
result = new ArrayList<>(result);
result.addAll(Arrays.asList(innerRepo.getArtifactDescriptors(key)));
return result.toArray(new IArtifactDescriptor[result.size()]);
}
@Override
public synchronized boolean contains(IArtifactDescriptor descriptor) {
return descriptorsToAdd.contains(descriptor) || innerRepo.contains(descriptor);
}
@Override
public synchronized boolean contains(IArtifactKey key) {
return artifactMap.containsKey(key) || innerRepo.contains(key);
}
@Override
public IStatus getArtifact(IArtifactDescriptor descriptor, OutputStream destination, IProgressMonitor monitor) {
return innerRepo.getArtifact(descriptor, destination, monitor);
}
@Override
public IStatus getRawArtifact(IArtifactDescriptor descriptor, OutputStream destination, IProgressMonitor monitor) {
return innerRepo.getRawArtifact(descriptor, destination, monitor);
}
@Override
public IStatus getArtifacts(IArtifactRequest[] requests, IProgressMonitor monitor) {
return Status.OK_STATUS;
}
@Override
public OutputStream getOutputStream(IArtifactDescriptor descriptor) {
return null;
}
@Override
public synchronized final void removeAll(IProgressMonitor monitor) {
try {
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
IArtifactDescriptor[] toRemove = descriptorsToAdd.toArray(new IArtifactDescriptor[descriptorsToAdd.size()]);
for (IArtifactDescriptor toRemove1 : toRemove) {
doRemoveArtifact(toRemove1);
}
subMonitor.worked(1);
} finally {
if (monitor != null)
monitor.done();
}
}
@Override
@Deprecated
public synchronized void removeAll() {
this.removeAll(new NullProgressMonitor());
}
@Override
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();
}
}
@Override
@Deprecated
public final synchronized void removeDescriptor(IArtifactDescriptor descriptor) {
removeDescriptor(descriptor, new NullProgressMonitor());
}
@Override
public synchronized void removeDescriptor(IArtifactKey key, IProgressMonitor monitor) {
try {
IArtifactDescriptor[] toRemove = getArtifactDescriptors(key);
SubMonitor subMonitor = SubMonitor.convert(monitor, toRemove.length);
for (IArtifactDescriptor toRemove1 : toRemove) {
doRemoveArtifact(toRemove1);
subMonitor.worked(1);
}
} finally {
if (monitor != null)
monitor.done();
}
}
@Override
@Deprecated
public final synchronized void removeDescriptor(IArtifactKey key) {
this.removeDescriptor(key, new NullProgressMonitor());
}
@Override
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();
}
}
@Override
@Deprecated
public final synchronized void removeDescriptors(IArtifactDescriptor[] descriptors) {
removeDescriptors(descriptors, new NullProgressMonitor());
}
@Override
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();
}
}
@Override
@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;
}
@Override
public String getDescription() {
return innerRepo.getDescription();
}
@Override
public URI getLocation() {
return innerRepo.getLocation();
}
@Override
public String getName() {
return innerRepo.getName();
}
@Override
public Map<String, String> getProperties() {
// TODO need to combine the local and inner properties
return innerRepo.getProperties();
}
@Override
public String getProperty(String key) {
return innerRepo.getProperty(key);
}
@Override
public String getProvider() {
return innerRepo.getProvider();
}
@Override
public IProvisioningAgent getProvisioningAgent() {
return innerRepo.getProvisioningAgent();
}
@Override
public String getType() {
return innerRepo.getType();
}
@Override
public String getVersion() {
return innerRepo.getVersion();
}
@Override
public boolean isModifiable() {
return innerRepo.isModifiable();
}
@Override
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();
}
}
@Override
public final String setProperty(String key, String value) {
return setProperty(key, value, new NullProgressMonitor());
}
@Override
public <T> T getAdapter(Class<T> adapter) {
return innerRepo.getAdapter(adapter);
}
@Override
public File getArtifactFile(IArtifactKey key) {
if (innerRepo instanceof IFileArtifactRepository)
return ((IFileArtifactRepository) innerRepo).getArtifactFile(key);
return null;
}
@Override
public File getArtifactFile(IArtifactDescriptor descriptor) {
if (innerRepo instanceof IFileArtifactRepository)
return ((IFileArtifactRepository) innerRepo).getArtifactFile(descriptor);
return null;
}
@Override
public IArtifactDescriptor createArtifactDescriptor(IArtifactKey key) {
return innerRepo.createArtifactDescriptor(key);
}
@Override
public IArtifactKey createArtifactKey(String classifier, String id, Version version) {
return innerRepo.createArtifactKey(classifier, id, version);
}
@Override
public IQueryable<IArtifactDescriptor> descriptorQueryable() {
final Collection<List<IArtifactDescriptor>> descs = artifactMap.values();
IQueryable<IArtifactDescriptor> cached = (query, monitor) -> query.perform(new CompoundIterator<IArtifactDescriptor>(descs.iterator()));
return QueryUtil.compoundQueryable(cached, innerRepo.descriptorQueryable());
}
@Override
public IQueryResult<IArtifactKey> query(IQuery<IArtifactKey> query, IProgressMonitor monitor) {
final Iterator<IArtifactKey> keyIterator = artifactMap.keySet().iterator();
IQueryable<IArtifactKey> cached = (q, mon) -> q.perform(keyIterator);
IQueryable<IArtifactKey> compound = QueryUtil.compoundQueryable(cached, innerRepo);
return compound.query(query, monitor);
}
@Override
public IStatus executeBatch(IRunnableWithProgress runnable, IProgressMonitor monitor) {
try {
runnable.run(monitor);
} catch (OperationCanceledException oce) {
return new Status(IStatus.CANCEL, Constants.BUNDLE_ID, oce.getMessage(), oce);
} catch (Exception e) {
return new Status(IStatus.ERROR, Constants.BUNDLE_ID, e.getMessage(), e);
}
return Status.OK_STATUS;
}
}