blob: 702058f1283e9cd93d72021be687eb6716700c1a [file] [log] [blame]
/*
* Copyright (c) 2014-2016 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.p2.internal.core;
import org.eclipse.oomph.p2.ProfileDefinition;
import org.eclipse.oomph.p2.Repository;
import org.eclipse.oomph.p2.core.Agent;
import org.eclipse.oomph.p2.core.BundlePool;
import org.eclipse.oomph.p2.core.P2Util;
import org.eclipse.oomph.p2.core.Profile;
import org.eclipse.oomph.util.IORuntimeException;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.SubMonitor;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* @author Eike Stepper
*/
public final class AgentAnalyzer
{
private final Agent agent;
private final Map<File, AnalyzedBundlePool> bundlePools = new HashMap<File, AnalyzedBundlePool>();
private final CountDownLatch analyzeLatch;
private final List<Job> analyzeProfileJobs = new ArrayList<Job>();
private Set<URI> repositoryURIs;
private Handler handler;
public AgentAnalyzer(Agent agent, boolean analyzeDamage, Handler handler, IProgressMonitor monitor)
{
this.agent = agent;
this.handler = handler;
Collection<Profile> allProfiles = agent.getAllProfiles();
monitor.beginTask("Loading profiles...", allProfiles.size());
try
{
for (Profile p2Profile : allProfiles)
{
P2CorePlugin.checkCancelation(monitor);
if (p2Profile.isValid())
{
monitor.subTask(p2Profile.getProfileId());
BundlePool p2BundlePool = p2Profile.getBundlePool();
if (p2BundlePool != null)
{
File installFolder = p2Profile.getInstallFolder();
File location = p2BundlePool.getLocation();
if (!location.equals(installFolder))
{
AnalyzedBundlePool bundlePool = bundlePools.get(location);
if (bundlePool == null)
{
bundlePool = new AnalyzedBundlePool(this, location);
bundlePools.put(location, bundlePool);
}
bundlePool.addProfile(p2Profile, installFolder);
}
}
}
monitor.worked(1);
}
}
finally
{
monitor.done();
}
if (handler != null)
{
handler.analyzerChanged(this);
}
analyzeLatch = new CountDownLatch(bundlePools.size());
for (AnalyzedBundlePool bundlePool : bundlePools.values())
{
Job job = bundlePool.analyze(analyzeLatch, analyzeDamage);
analyzeProfileJobs.add(job);
}
}
public void awaitAnalyzing(IProgressMonitor monitor)
{
int totalWork = bundlePools.size();
SubMonitor progress = SubMonitor.convert(monitor, "Analyzing...", totalWork).detectCancelation();
progress.subTask("Analyzing artifacts...");
int work = totalWork - (int)analyzeLatch.getCount();
if (work != 0)
{
progress.worked(work);
}
try
{
while (!analyzeLatch.await(100, TimeUnit.MILLISECONDS))
{
P2CorePlugin.checkCancelation(monitor);
int newWork = totalWork - (int)analyzeLatch.getCount();
if (newWork != work)
{
progress.worked(newWork - work);
work = newWork;
}
}
}
catch (InterruptedException ex)
{
//$FALL-THROUGH$
}
finally
{
progress.done();
}
}
public void dispose()
{
handler = null;
for (Job job : analyzeProfileJobs)
{
job.cancel();
}
analyzeProfileJobs.clear();
bundlePools.clear();
}
public Map<File, AnalyzedBundlePool> getBundlePools()
{
return bundlePools;
}
public Set<URI> getRepositoryURIs()
{
if (repositoryURIs == null)
{
repositoryURIs = new HashSet<URI>();
IArtifactRepositoryManager repositoryManager = agent.getArtifactRepositoryManager();
// addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_ALL);
// addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_DISABLED);
// addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_LOCAL);
// addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_NON_LOCAL);
// addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_SYSTEM);
addURIs(repositoryURIs, repositoryManager, IRepositoryManager.REPOSITORIES_NON_SYSTEM);
for (AnalyzedBundlePool bundlePool : bundlePools.values())
{
// Don't use possibly damaged local bundle pools for damage repair
repositoryURIs.remove(bundlePool.getLocation().toURI());
}
}
return repositoryURIs;
}
private void analyzerChanged(AgentAnalyzer analyzer)
{
if (handler != null)
{
handler.analyzerChanged(analyzer);
}
}
private void bundlePoolChanged(AnalyzedBundlePool bundlePool, boolean artifacts, boolean profiles)
{
if (handler != null)
{
handler.bundlePoolChanged(bundlePool, artifacts, profiles);
}
}
private void profileChanged(AnalyzedProfile profile)
{
if (handler != null)
{
handler.profileChanged(profile);
}
}
private void artifactChanged(AnalyzedArtifact artifact)
{
if (handler != null)
{
handler.artifactChanged(artifact);
}
}
private void addURIs(Set<URI> repos, IArtifactRepositoryManager repositoryManager, int flag)
{
for (URI uri : repositoryManager.getKnownRepositories(flag))
{
repos.add(uri);
}
}
/**
* @author Eike Stepper
*/
public interface Handler
{
public void analyzerChanged(AgentAnalyzer analyzer);
public void bundlePoolChanged(AnalyzedBundlePool bundlePool, boolean artifacts, boolean profiles);
public void profileChanged(AnalyzedProfile profile);
public void artifactChanged(AnalyzedArtifact artifact);
}
/**
* @author Eike Stepper
*/
public static final class AnalyzedBundlePool implements Comparable<AnalyzedBundlePool>
{
private final AgentAnalyzer analyzer;
private final File location;
private final Set<URI> repositoryURIs = new LinkedHashSet<URI>();
private final List<AnalyzedProfile> profiles = new ArrayList<AnalyzedProfile>();
private final Map<IArtifactKey, AnalyzedArtifact> artifacts = new HashMap<IArtifactKey, AnalyzedArtifact>();
private final Set<AnalyzedArtifact> unusedArtifacts = new HashSet<AnalyzedArtifact>();
private final Set<AnalyzedArtifact> damagedArtifacts = new HashSet<AnalyzedArtifact>();
private int damagedArtifactsPercent;
private AnalyzedArtifact[] artifactsArray;
private AnalyzedArtifact[] unusedArtifactsArray;
private AnalyzedArtifact[] damagedArtifactsArray;
private IFileArtifactRepository p2BundlePool;
private boolean analyzing = true;
private boolean analyzingDamage = true;
public AnalyzedBundlePool(AgentAnalyzer analyzer, File location)
{
this.analyzer = analyzer;
this.location = location;
}
public boolean isAnalyzing()
{
return analyzing;
}
public AgentAnalyzer getAnalyzer()
{
return analyzer;
}
public File getLocation()
{
return location;
}
public Set<URI> getRepositoryURIs()
{
return repositoryURIs;
}
public int getProfilesCount()
{
synchronized (this)
{
return profiles.size();
}
}
public AnalyzedProfile[] getProfiles()
{
synchronized (this)
{
return profiles.toArray(new AnalyzedProfile[profiles.size()]);
}
}
public AnalyzedProfile[] getUnusedProfiles()
{
List<AnalyzedProfile> unusedProfiles = new ArrayList<AnalyzedProfile>();
synchronized (this)
{
for (AnalyzedProfile profile : profiles)
{
if (profile.isUnused())
{
unusedProfiles.add(profile);
}
}
}
return unusedProfiles.toArray(new AnalyzedProfile[unusedProfiles.size()]);
}
public int getUnusedProfilesCount()
{
int count = 0;
synchronized (this)
{
for (AnalyzedProfile profile : profiles)
{
if (profile.isUnused())
{
++count;
}
}
}
return count;
}
public int getArtifactCount()
{
synchronized (this)
{
return artifacts.size();
}
}
public AnalyzedArtifact[] getArtifacts()
{
synchronized (this)
{
if (artifactsArray == null)
{
artifactsArray = artifacts.values().toArray(new AnalyzedArtifact[artifacts.size()]);
Arrays.sort(artifactsArray);
}
return artifactsArray;
}
}
public AnalyzedArtifact getArtifact(IArtifactKey key)
{
synchronized (this)
{
return artifacts.get(key);
}
}
public int getUnusedArtifactsCount()
{
synchronized (this)
{
return unusedArtifacts.size();
}
}
public AnalyzedArtifact[] getUnusedArtifacts()
{
synchronized (this)
{
if (unusedArtifactsArray == null)
{
unusedArtifactsArray = unusedArtifacts.toArray(new AnalyzedArtifact[unusedArtifacts.size()]);
Arrays.sort(unusedArtifactsArray);
}
return unusedArtifactsArray;
}
}
public int getDamagedArtifactsPercent()
{
return damagedArtifactsPercent;
}
public int getDamagedArtifactsCount()
{
synchronized (damagedArtifacts)
{
return damagedArtifacts.size();
}
}
public AnalyzedArtifact[] getDamagedArtifacts()
{
synchronized (this)
{
if (damagedArtifactsArray == null)
{
damagedArtifactsArray = damagedArtifacts.toArray(new AnalyzedArtifact[damagedArtifacts.size()]);
Arrays.sort(damagedArtifactsArray);
}
return damagedArtifactsArray;
}
}
public boolean isAnalyzingDamage()
{
return analyzingDamage;
}
public int compareTo(AnalyzedBundlePool o)
{
return location.getAbsolutePath().compareTo(o.getLocation().getAbsolutePath());
}
@Override
public String toString()
{
return location.toString();
}
synchronized IFileArtifactRepository getP2BundlePool(IProgressMonitor monitor)
{
if (p2BundlePool == null)
{
try
{
IArtifactRepositoryManager repositoryManager = analyzer.agent.getArtifactRepositoryManager();
p2BundlePool = (IFileArtifactRepository)repositoryManager.loadRepository(location.toURI(), monitor);
}
catch (ProvisionException ex)
{
throw new IllegalStateException(ex);
}
}
return p2BundlePool;
}
AnalyzedProfile addProfile(Profile p2Profile, File installFolder)
{
AnalyzedProfile profile = new AnalyzedProfile(this, p2Profile, installFolder);
repositoryURIs.addAll(profile.getRepositoryURIs());
synchronized (this)
{
profiles.add(profile);
Collections.sort(profiles);
}
return profile;
}
Job analyze(final CountDownLatch analyzeLatch, final boolean analyzeDamage)
{
Job job = new Job("Analyzing bundle pool " + location)
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
analyze(analyzeDamage, monitor);
analyzeLatch.countDown();
return Status.OK_STATUS;
}
};
job.schedule();
return job;
}
private void analyze(boolean analyzeDamage, IProgressMonitor monitor)
{
Random random = new Random(System.currentTimeMillis());
IFileArtifactRepository p2BundlePool = getP2BundlePool(monitor);
for (IArtifactKey key : P2Util.asIterable(p2BundlePool.query(ArtifactKeyQuery.ALL_KEYS, monitor)))
{
P2CorePlugin.checkCancelation(monitor);
File file = p2BundlePool.getArtifactFile(key);
AnalyzedArtifact artifact = new AnalyzedArtifact(this, key, file);
synchronized (this)
{
artifacts.put(key, artifact);
artifactsArray = null;
}
if (random.nextInt(100) < 2)
{
analyzer.bundlePoolChanged(this, false, false);
}
}
analyzer.bundlePoolChanged(this, true, false);
for (AnalyzedProfile profile : getProfiles())
{
P2CorePlugin.checkCancelation(monitor);
profile.analyze(monitor);
}
analyzer.analyzerChanged(analyzer);
analyzeUnusedArtifacts(monitor);
analyzing = false;
if (analyzeDamage)
{
analyzeDamagedArtifacts(monitor);
}
}
private void analyzeUnusedArtifacts(IProgressMonitor monitor)
{
for (AnalyzedArtifact artifact : getArtifacts())
{
P2CorePlugin.checkCancelation(monitor);
if (analyzeUnusedArtifact(artifact, monitor))
{
synchronized (this)
{
unusedArtifacts.add(artifact);
unusedArtifactsArray = null;
}
analyzer.bundlePoolChanged(this, false, false);
}
}
analyzer.bundlePoolChanged(this, true, false);
}
private boolean analyzeUnusedArtifact(AnalyzedArtifact artifact, IProgressMonitor monitor)
{
for (AnalyzedProfile profile : getProfiles())
{
P2CorePlugin.checkCancelation(monitor);
if (profile.getArtifacts().contains(artifact))
{
return false;
}
}
return true;
}
private void analyzeDamagedArtifacts(IProgressMonitor monitor)
{
AnalyzedArtifact[] artifacts = getArtifacts();
int total = artifacts.length;
int i = 0;
for (AnalyzedArtifact artifact : artifacts)
{
P2CorePlugin.checkCancelation(monitor);
int percent = ++i * 100 / total;
if (percent != damagedArtifactsPercent)
{
damagedArtifactsPercent = percent;
analyzer.bundlePoolChanged(this, false, false);
}
synchronized (artifact)
{
IArtifactKey key = artifact.getKey();
if (getArtifact(key) == null)
{
// Continue with next artifact if this artifact was deleted meanwhile
continue;
}
}
monitor.subTask("Validating " + artifact);
if (isDamaged(artifact))
{
synchronized (this)
{
damagedArtifacts.add(artifact);
damagedArtifactsArray = null;
}
analyzer.bundlePoolChanged(this, false, false);
artifact.setDamaged();
analyzer.artifactChanged(artifact);
}
}
analyzer.bundlePoolChanged(this, false, false);
analyzingDamage = false;
}
@SuppressWarnings("restriction")
private static boolean isDamaged(AnalyzedArtifact artifact)
{
File file = artifact.getFile();
if (file == null || !file.exists())
{
return true;
}
if (file.isFile())
{
ZipFile zipFile = null;
try
{
zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
if (!entries.hasMoreElements())
{
return true;
}
do
{
ZipEntry entry = entries.nextElement();
entry.getName();
entry.getCompressedSize();
entry.getCrc();
InputStream inputStream = null;
try
{
inputStream = zipFile.getInputStream(entry);
if (inputStream == null)
{
return true;
}
}
finally
{
IOUtil.close(inputStream);
}
} while (entries.hasMoreElements());
}
catch (Exception ex)
{
return true;
}
finally
{
try
{
if (zipFile != null)
{
zipFile.close();
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
}
try
{
String type = artifact.getType();
org.eclipse.equinox.p2.publisher.AbstractPublisherAction action;
String namespace;
if (AnalyzedArtifact.TYPE_FEATURE.equals(type))
{
action = new org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction(new File[] { file });
namespace = "org.eclipse.update.feature";
}
else if (AnalyzedArtifact.TYPE_PLUGIN.equals(type))
{
action = new org.eclipse.equinox.p2.publisher.eclipse.BundlesAction(new File[] { file });
namespace = "osgi.bundle";
}
else
{
return false;
}
org.eclipse.equinox.p2.publisher.PublisherInfo info = new org.eclipse.equinox.p2.publisher.PublisherInfo();
org.eclipse.equinox.p2.publisher.PublisherResult result = new org.eclipse.equinox.p2.publisher.PublisherResult();
action.perform(info, result, new NullProgressMonitor());
IArtifactKey key = artifact.getKey();
String id = key.getId();
Version version = key.getVersion();
for (Iterator<IInstallableUnit> it = result.everything(); it.hasNext();)
{
IInstallableUnit iu = it.next();
for (IProvidedCapability capability : iu.getProvidedCapabilities())
{
String name = capability.getName();
String capabilityNamespace = capability.getNamespace();
Version capabilityVersion = capability.getVersion();
if (namespace.equals(capabilityNamespace) && id.equals(name) && version.equals(capabilityVersion))
{
return false;
}
}
}
}
catch (Exception exception)
{
return true;
}
return true;
}
}
/**
* @author Eike Stepper
*/
public static final class AnalyzedProfile implements Comparable<AnalyzedProfile>
{
public static final String ECLIPSE = "Eclipse";
public static final String TARGLET = "Targlet";
public static final String UNKNOWN = "Unknown";
@Deprecated
private static final String PROP_TARGLET_CONTAINER_ID = "targlet.container.id";
private final AnalyzedBundlePool bundlePool;
private final Profile p2Profile;
private final File installFolder;
private final String type;
private final int roots;
private final Set<URI> repositoryURIs = new LinkedHashSet<URI>();
private final Set<AnalyzedArtifact> artifacts = new HashSet<AnalyzedArtifact>();
private final Set<AnalyzedArtifact> damagedArtifacts = new HashSet<AnalyzedArtifact>();
private AnalyzedArtifact[] damagedArtifactsArray;
public AnalyzedProfile(AnalyzedBundlePool bundlePool, Profile p2Profile, File installFolder)
{
this.bundlePool = bundlePool;
this.p2Profile = p2Profile;
this.installFolder = installFolder;
if (p2Profile.getProperty(PROP_TARGLET_CONTAINER_ID) != null)
{
type = TARGLET;
}
else if (installFolder != null)
{
type = ECLIPSE;
}
else
{
type = UNKNOWN;
}
ProfileDefinition profileDefinition = p2Profile.getDefinition();
roots = profileDefinition.getRequirements().size();
for (Repository repository : profileDefinition.getRepositories())
{
try
{
repositoryURIs.add(new URI(repository.getURL()));
}
catch (URISyntaxException ex)
{
P2CorePlugin.INSTANCE.log(ex);
}
}
}
public AnalyzedBundlePool getBundlePool()
{
return bundlePool;
}
public Profile getP2Profile()
{
return p2Profile;
}
public boolean isUnused()
{
return !p2Profile.isUsed();
}
public String getID()
{
return p2Profile.getProfileId();
}
public File getInstallFolder()
{
return installFolder;
}
public String getType()
{
return type;
}
public final int getRoots()
{
return roots;
}
public Set<URI> getRepositoryURIs()
{
return repositoryURIs;
}
public Set<AnalyzedArtifact> getArtifacts()
{
return artifacts;
}
public boolean isDamaged()
{
synchronized (bundlePool)
{
return !damagedArtifacts.isEmpty();
}
}
public int getDamagedArtifactsCount()
{
synchronized (bundlePool)
{
return damagedArtifacts.size();
}
}
public AnalyzedArtifact[] getDamagedArtifacts()
{
synchronized (bundlePool)
{
if (damagedArtifactsArray == null)
{
damagedArtifactsArray = damagedArtifacts.toArray(new AnalyzedArtifact[damagedArtifacts.size()]);
Arrays.sort(damagedArtifactsArray);
}
return damagedArtifactsArray;
}
}
public int compareTo(AnalyzedProfile o)
{
return getID().compareTo(o.getID());
}
@Override
public String toString()
{
return getID();
}
void analyze(IProgressMonitor monitor)
{
for (IInstallableUnit iu : P2Util.asIterable(p2Profile.query(QueryUtil.createIUAnyQuery(), monitor)))
{
for (IArtifactKey key : iu.getArtifacts())
{
AnalyzedArtifact artifact = bundlePool.getArtifact(key);
if (artifact != null)
{
synchronized (bundlePool)
{
artifacts.add(artifact);
artifact.addProfile(this);
}
bundlePool.analyzer.profileChanged(this);
}
}
}
}
public synchronized void delete(IProgressMonitor monitor)
{
if (isUnused())
{
monitor.subTask("Deleting " + this);
p2Profile.delete();
boolean artifactsChanged = false;
synchronized (bundlePool)
{
for (AnalyzedArtifact artifact : artifacts)
{
if (artifact.profiles.remove(this))
{
artifactsChanged = true;
if (artifact.profiles.isEmpty())
{
bundlePool.unusedArtifacts.add(artifact);
bundlePool.unusedArtifactsArray = null;
}
}
}
bundlePool.profiles.remove(this);
}
bundlePool.analyzer.bundlePoolChanged(bundlePool, true, true);
bundlePool.analyzer.profileChanged(this);
if (artifactsChanged)
{
bundlePool.analyzer.artifactChanged(null);
}
}
}
}
/**
* @author Eike Stepper
*/
public static final class AnalyzedArtifact implements Comparable<AnalyzedArtifact>
{
public static final String REPAIR_TASK_NAME = "Repairing artifacts";
public static final String TYPE_FEATURE = "Feature";
public static final String TYPE_PLUGIN = "Plugin";
public static final String TYPE_BINARY = "Binary";
private final AnalyzedBundlePool bundlePool;
private final IArtifactKey key;
private final String type;
private final File file;
private final List<AnalyzedProfile> profiles = new ArrayList<AnalyzedProfile>();
private boolean damaged;
public AnalyzedArtifact(AnalyzedBundlePool bundlePool, IArtifactKey key, File file)
{
this.bundlePool = bundlePool;
this.key = key;
this.file = file;
String classifier = key.getClassifier();
if ("org.eclipse.update.feature".equals(classifier))
{
type = TYPE_FEATURE;
}
else if ("osgi.bundle".equals(classifier))
{
type = TYPE_PLUGIN;
}
else
{
type = TYPE_BINARY;
}
}
public boolean isUnused()
{
return profiles.isEmpty();
}
public boolean isDamaged()
{
return damaged;
}
public AnalyzedBundlePool getBundlePool()
{
return bundlePool;
}
public IArtifactKey getKey()
{
return key;
}
public String getType()
{
return type;
}
public String getID()
{
return key.getId();
}
public String getVersion()
{
return key.getVersion().toString();
}
public File getFile()
{
return file;
}
public List<AnalyzedProfile> getProfiles()
{
return profiles;
}
public int compareTo(AnalyzedArtifact o)
{
int result = key.getId().compareTo(o.key.getId());
if (result == 0)
{
result = key.getVersion().compareTo(o.key.getVersion());
if (result == 0)
{
result = type.compareTo(o.type);
}
}
return result;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + (key == null ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
AnalyzedArtifact other = (AnalyzedArtifact)obj;
if (key == null)
{
if (other.key != null)
{
return false;
}
}
else if (!key.equals(other.key))
{
return false;
}
return true;
}
@Override
public String toString()
{
return key.getId() + " " + key.getVersion();
}
void addProfile(AnalyzedProfile profile)
{
profiles.add(profile);
}
void setDamaged()
{
damaged = true;
for (AnalyzedProfile profile : profiles)
{
synchronized (bundlePool)
{
profile.damagedArtifacts.add(this);
profile.damagedArtifactsArray = null;
}
bundlePool.analyzer.handler.profileChanged(profile);
}
}
public synchronized void delete(IProgressMonitor monitor)
{
if (isUnused())
{
deleteUnused(monitor);
}
else
{
monitor.subTask("Deleting " + this);
IOUtil.deleteBestEffort(file);
damaged = true;
synchronized (bundlePool)
{
bundlePool.damagedArtifacts.add(this);
bundlePool.damagedArtifactsArray = null;
}
bundlePool.analyzer.bundlePoolChanged(bundlePool, false, false);
bundlePool.analyzer.artifactChanged(this);
for (AnalyzedProfile profile : profiles)
{
synchronized (bundlePool)
{
profile.damagedArtifacts.add(this);
profile.damagedArtifactsArray = null;
}
bundlePool.analyzer.profileChanged(profile);
}
}
}
private void deleteUnused(IProgressMonitor monitor)
{
monitor.subTask("Deleting " + this);
IFileArtifactRepository p2BundlePool = bundlePool.getP2BundlePool(monitor);
p2BundlePool.removeDescriptor(key, monitor);
damaged = false;
synchronized (bundlePool)
{
bundlePool.artifacts.remove(key);
bundlePool.artifactsArray = null;
bundlePool.unusedArtifacts.remove(this);
bundlePool.unusedArtifactsArray = null;
bundlePool.damagedArtifacts.remove(this);
bundlePool.damagedArtifactsArray = null;
}
bundlePool.analyzer.bundlePoolChanged(bundlePool, true, false);
}
public synchronized boolean repair(Set<URI> repositoryURIs, IProgressMonitor monitor)
{
if (!damaged)
{
return false;
}
if (isUnused())
{
deleteUnused(monitor);
return true;
}
monitor.subTask("Repairing " + this);
if (repositoryURIs == null ? doRepair(monitor) : doRepair(repositoryURIs, monitor))
{
damaged = false;
bundlePool.analyzer.artifactChanged(this);
synchronized (bundlePool)
{
bundlePool.damagedArtifacts.remove(this);
bundlePool.damagedArtifactsArray = null;
}
for (AnalyzedProfile profile : profiles)
{
synchronized (bundlePool)
{
profile.damagedArtifacts.remove(this);
profile.damagedArtifactsArray = null;
}
bundlePool.analyzer.profileChanged(profile);
}
bundlePool.analyzer.bundlePoolChanged(bundlePool, false, false);
return true;
}
return false;
}
private boolean doRepair(IProgressMonitor monitor)
{
Set<URI> repositoryURIs = bundlePool.getRepositoryURIs();
SubMonitor progress = SubMonitor.convert(monitor, 1 + repositoryURIs.size()).detectCancelation();
Set<URI> poolURIs = new HashSet<URI>();
for (AnalyzedBundlePool pool : bundlePool.analyzer.getBundlePools().values())
{
if (pool != bundlePool)
{
AnalyzedArtifact otherArtifact = pool.getArtifact(key);
if (otherArtifact != null && !otherArtifact.isDamaged())
{
URI uri = pool.getLocation().toURI();
poolURIs.add(uri);
}
}
}
if (!poolURIs.isEmpty())
{
if (doRepair(poolURIs, progress))
{
return true;
}
}
if (!repositoryURIs.isEmpty())
{
if (doRepair(repositoryURIs, progress))
{
return true;
}
}
return false;
}
private boolean doRepair(Set<URI> repositoryURIs, IProgressMonitor monitor)
{
SubMonitor progress = SubMonitor.convert(monitor, repositoryURIs.size()).detectCancelation();
for (URI uri : repositoryURIs)
{
if (doRepair(uri, progress.newChild()))
{
return true;
}
}
return false;
}
private boolean doRepair(URI repositoryURI, SubMonitor progress)
{
IFileArtifactRepository p2BundlePool = bundlePool.getP2BundlePool(progress.newChild());
IArtifactDescriptor[] localDescriptors = null;
try
{
localDescriptors = p2BundlePool.getArtifactDescriptors(key);
if (localDescriptors == null || localDescriptors.length == 0)
{
return false;
}
p2BundlePool.removeDescriptors(localDescriptors, progress.newChild());
IArtifactRepositoryManager repositoryManager = bundlePool.analyzer.agent.getArtifactRepositoryManager();
IArtifactRepository repository = repositoryManager.loadRepository(repositoryURI, progress.newChild());
progress.setTaskName(REPAIR_TASK_NAME);
IArtifactDescriptor[] remoteDescriptors = repository.getArtifactDescriptors(key);
for (IArtifactDescriptor remoteDescriptor : remoteDescriptors)
{
OutputStream destination = null;
try
{
destination = p2BundlePool.getOutputStream(localDescriptors[0]);
IStatus status = repository.getArtifact(remoteDescriptor, destination, progress.newChild());
if (status.getSeverity() == IStatus.OK)
{
localDescriptors = null;
return true;
}
}
finally
{
IOUtil.close(destination);
}
}
}
catch (OperationCanceledException ex)
{
throw ex;
}
catch (Error err)
{
throw err;
}
catch (Exception ex)
{
P2CorePlugin.INSTANCE.log(ex);
}
finally
{
restoreDescriptors(p2BundlePool, localDescriptors);
}
return false;
}
private void restoreDescriptors(IFileArtifactRepository p2BundlePool, IArtifactDescriptor[] oldDescriptors)
{
if (oldDescriptors != null && oldDescriptors.length != 0)
{
try
{
p2BundlePool.addDescriptors(oldDescriptors, new NullProgressMonitor());
}
catch (Exception ex)
{
P2CorePlugin.INSTANCE.log(ex);
}
}
}
}
}