blob: e5734742fac1fb2d5d8ca4d9e823fb6a1bfda089 [file] [log] [blame]
/*
* Copyright (c) 2019 Ed Merks 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:
* Ed Merks - initial API and implementation
*/
package org.eclipse.oomph.p2.internal.core;
import org.eclipse.oomph.junit.JUnitFactory;
import org.eclipse.oomph.junit.JUnitPackage;
import org.eclipse.oomph.junit.ProblemType;
import org.eclipse.oomph.junit.TestCaseType;
import org.eclipse.oomph.junit.TestSuite;
import org.eclipse.oomph.p2.P2Factory;
import org.eclipse.oomph.p2.Requirement;
import org.eclipse.oomph.p2.core.Agent;
import org.eclipse.oomph.p2.core.P2Util;
import org.eclipse.oomph.p2.internal.core.RepositoryIntegrityAnalyzer.InstallableUnitWriter.ValueHandler;
import org.eclipse.oomph.util.CollectionUtil;
import org.eclipse.oomph.util.IORuntimeException;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.ObjectUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.oomph.util.XMLUtil;
import org.eclipse.oomph.util.ZIPUtil;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.URIConverter.ReadableInputStream;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLOptions;
import org.eclipse.emf.ecore.xmi.XMLParserPool;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.XMLSave;
import org.eclipse.emf.ecore.xmi.impl.GenericXMLResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLOptionsImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLString;
import org.eclipse.emf.ecore.xml.type.AnyType;
import org.eclipse.emf.ecore.xml.type.XMLTypeDocumentRoot;
import org.eclipse.emf.ecore.xml.type.XMLTypeFactory;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPPublicKeyStore;
import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPSignatureVerifier;
import org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository;
import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository;
import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability;
import org.eclipse.equinox.internal.p2.metadata.RequiredCapability;
import org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository;
import org.eclipse.equinox.internal.p2.metadata.repository.io.MetadataWriter;
import org.eclipse.equinox.internal.p2.metadata.repository.io.XMLConstants;
import org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryIO;
import org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryState;
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.ILicense;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.ICompositeRepository;
import org.eclipse.equinox.p2.repository.IRepository;
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.IProcessingStepDescriptor;
import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.repository.spi.PGPPublicKeyService;
import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
import org.eclipse.osgi.signedcontent.SignedContent;
import org.eclipse.osgi.signedcontent.SignedContentFactory;
import org.eclipse.osgi.signedcontent.SignerInfo;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.security.auth.x500.X500Principal;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringWriter;
import java.math.RoundingMode;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Ed Merks
*/
@SuppressWarnings({ "restriction", "nls" })
public class RepositoryIntegrityAnalyzer implements IApplication
{
private static final Comparator<List<Certificate>> CERTIFICATE_COMPARATOR = new Comparator<>()
{
@Override
public int compare(List<Certificate> o1, List<Certificate> o2)
{
int size = o1.size();
int result = Integer.compare(size, o2.size());
if (result == 0 && size != 0)
{
X509Certificate certificate1 = (X509Certificate)o1.get(0);
X509Certificate certificate2 = (X509Certificate)o2.get(0);
result = certificate1.getSubjectX500Principal().getName().compareTo(certificate2.getSubjectX500Principal().getName());
}
return result;
}
};
private static final Comparator<PGPPublicKey> PGP_COMPARATOR = new Comparator<PGPPublicKey>()
{
@Override
public int compare(PGPPublicKey o1, PGPPublicKey o2)
{
return PGPPublicKeyService.toHexFingerprint(o1).compareTo(PGPPublicKeyService.toHexFingerprint(o2));
}
};
private static final String DOWNLOAD_ECLIPSE_ORG_AUTHORITY = "download.eclipse.org";
private static final File DOWNLOAD_ECLIPSE_ORG_FOLDER = new File("/home/data/httpd/" + DOWNLOAD_ECLIPSE_ORG_AUTHORITY);
private static final boolean DOWNLOAD_ECLIPSE_ORG_FOLDER_EXISTS = DOWNLOAD_ECLIPSE_ORG_FOLDER.exists();
private static final String DOWNLOAD_ECLIPSE_ORG_FOLDER_URI = DOWNLOAD_ECLIPSE_ORG_FOLDER.toURI().toString();
private static final String DOWNLOAD_ECLIPSE_ORG_SERVER_URI = "https://" + DOWNLOAD_ECLIPSE_ORG_AUTHORITY + "/";
private static final String PROCESSED = ".processed";
private static final int DOWNLOAD_RETRY_COUNT = 3;
private static final Comparator<IInstallableUnit> NAME_VERSION_COMPARATOR = new Comparator<>()
{
private final Comparator<String> comparator = CommonPlugin.INSTANCE.getComparator();
@Override
public int compare(IInstallableUnit iu1, IInstallableUnit iu2)
{
String name1 = iu1.getProperty(IInstallableUnit.PROP_NAME, null);
if (name1 == null)
{
name1 = iu1.getId();
}
String name2 = iu2.getProperty(IInstallableUnit.PROP_NAME, null);
if (name2 == null)
{
name2 = iu2.getId();
}
int result = comparator.compare(name1, name2);
if (result == 0)
{
result = iu1.getVersion().compareTo(iu2.getVersion());
}
return result;
}
};
private final Map<String, Report.LicenseDetail> details = new LinkedHashMap<>();
private final Map<URI, Report> reports = new LinkedHashMap<>();
private final Map<java.net.URI, IMetadataRepository> metadataRepositories = new LinkedHashMap<>();
private final Map<java.net.URI, IArtifactRepository> artifactRepositories = new LinkedHashMap<>();
private final Map<URI, byte[]> imageBytes = new HashMap<>();
private final Map<Object, String> images = new HashMap<>();
private final Map<File, Future<List<String>>> fileIndices = new TreeMap<>();
private Agent agent;
private ExecutorService executor;
private boolean verbose;
private boolean aggregator;
@Override
public Object start(IApplicationContext context) throws Exception
{
try
{
String[] arguments = (String[])context.getArguments().get(IApplicationContext.APPLICATION_ARGS);
Set<URI> uris = new LinkedHashSet<>();
File outputLocation = new File(".").getCanonicalFile();
File publishLocation = null;
File testsLocation = null;
String reportSource = "https://ci.eclipse.org/oomph/job/repository-analyzer/";
String reportBranding = "https://wiki.eclipse.org/images/d/dc/Oomph_Project_Logo.png";
if (arguments != null)
{
for (int i = 0; i < arguments.length; ++i)
{
String option = arguments[i];
if ("-output".equals(option) || "-o".equals(option))
{
File file = new File(arguments[++i]);
outputLocation = file.getCanonicalFile();
}
else if ("-publish".equals(option) || "-p".equals(option))
{
File file = new File(arguments[++i]);
publishLocation = file.getCanonicalFile();
}
else if ("-source".equals(option) || "-s".equals(option))
{
reportSource = arguments[++i];
}
else if ("-branding".equals(option) || "-b".equals(option))
{
reportBranding = arguments[++i];
}
else if ("-verbose".equals(option) || "-v".equals(option))
{
verbose = true;
}
else if ("-aggregator".equals(option) || "-a".equals(option))
{
aggregator = true;
}
else if ("-test".equals(option) || "-t".equals(option))
{
File file = new File(arguments[++i]);
testsLocation = file.getCanonicalFile();
}
else
{
URI uri = URI.createURI(arguments[i]);
if ("".equals(uri.lastSegment()))
{
uri = uri.trimSegments(1);
}
uris.add(uri);
}
}
}
createFolders(outputLocation);
if (aggregator)
{
uris.addAll(loadAggregator(outputLocation));
}
CompositeMetadataRepository metadataRepository = CompositeMetadataRepository.createMemoryComposite(getAgent().getProvisioningAgent());
metadataRepositories.put(metadataRepository.getLocation(), metadataRepository);
for (URI uri : uris)
{
metadataRepository.addChild(toInternalRepositoryLocation(uri));
}
CompositeArtifactRepository artifactRepository = CompositeArtifactRepository.createMemoryComposite(getAgent().getProvisioningAgent());
artifactRepositories.put(metadataRepository.getLocation(), artifactRepository);
for (URI uri : uris)
{
artifactRepository.addChild(toInternalRepositoryLocation(uri));
}
File artifactCacheLocation = new File(outputLocation, "artifacts");
artifactCacheLocation.mkdir();
RepositoryIndex repositoryIndex = RepositoryIndex.create("\n");
Set<File> reportLocations = new HashSet<>();
Map<String, String> allReports = new TreeMap<>();
Set<File> reportsWithErrors = new HashSet<>();
if (testsLocation != null)
{
testsLocation.mkdirs();
for (File file : testsLocation.listFiles())
{
IOUtil.deleteBestEffort(file);
}
}
Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache = new LinkedHashMap<>();
for (URI uri : uris)
{
if (verbose)
{
System.out.println("Computing report information for '" + uri + "'");
}
String relativePath = toRelativePath(uri);
File reportLocation = new File(outputLocation, relativePath);
reportLocations.add(reportLocation);
// Clean it up before creating it.
IOUtil.deleteBestEffort(reportLocation);
createFolders(reportLocation);
Report report = generateReport(null, uri, outputLocation, uri, reportLocation, artifactCache, artifactCacheLocation, reportSource, reportBranding);
if (verbose)
{
System.out.println("Waiting for report information completion for '" + uri + "'");
}
shutDownExecutor();
emitReport(allReports, new HashSet<Report>(), report, reportLocation, testsLocation, repositoryIndex);
if (publishLocation != null)
{
File reportPublishLocation = new File(publishLocation, relativePath);
publish(reportLocation, reportPublishLocation);
if (verbose)
{
System.out.println("Publish report for '" + uri + "' to '" + reportPublishLocation);
}
}
if (aggregator)
{
if (!report.getUnsignedIUs().isEmpty() || !report.getBadProviderIUs().isEmpty() || !report.getBadLicenseIUs().isEmpty()
|| !report.getBrokenBrandingIUs().isEmpty())
{
reportsWithErrors.add(reportLocation);
}
}
images.clear();
reports.clear();
}
reportLocations.add(artifactCacheLocation);
if (aggregator)
{
reportLocations.add(new File(outputLocation, "aggrcons"));
}
IndexReport indexReport = new IndexReport(null, reportSource, reportBranding, outputLocation, publishLocation, reportLocations, allReports,
reportsWithErrors);
generateIndex(indexReport, repositoryIndex, reportSource, reportBranding);
}
finally
{
shutDownExecutor();
}
return null;
}
private Set<URI> loadAggregator(File outputLocation) throws IOException, ProvisionException, OperationCanceledException, URISyntaxException
{
ResourceSet resourceSet = new ResourceSetImpl();
final URIConverter uriConverter = resourceSet.getURIConverter();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new GenericXMLResourceFactoryImpl());
URI aggregatorURI = URI.createURI("https://git.eclipse.org/c/simrel/org.eclipse.simrel.build.git/plain/simrel.aggr");
Resource aggregatorResource = resourceSet.getResource(aggregatorURI, true);
// aggregatorResource.save(System.out, null);
Map<URI, Future<InputStream>> aggrcons = new LinkedHashMap<>();
ExecutorService executor = getExecutor();
for (Iterator<EObject> it = aggregatorResource.getAllContents(); it.hasNext();)
{
EObject eObject = it.next();
String href = get(eObject, "contributions", "href");
if (href != null)
{
URI uri = URI.createURI(href);
final URI resolvedURI = uri.resolve(aggregatorURI);
aggrcons.put(resolvedURI, executor.submit(new Callable<InputStream>()
{
@Override
public InputStream call() throws Exception
{
InputStream inputStream = null;
try
{
inputStream = uriConverter.createInputStream(resolvedURI);
ByteArrayOutputStream output = new ByteArrayOutputStream();
IOUtil.copy(inputStream, output);
output.close();
return new ByteArrayInputStream(output.toByteArray());
}
finally
{
IOUtil.closeSilent(inputStream);
}
}
}));
}
}
Set<URI> composites = new LinkedHashSet<>();
LOOP: for (Map.Entry<URI, Future<InputStream>> entry : aggrcons.entrySet())
{
URI aggrcon = entry.getKey();
URI repository = null;
Resource aggrconResource = resourceSet.createResource(aggrcon);
try
{
aggrconResource.load(entry.getValue().get(), null);
}
catch (Exception ex)
{
}
aggrconResource.save(System.out, null);
Map<URI, Set<Requirement>> requirements = new LinkedHashMap<>();
Set<String> contacts = new LinkedHashSet<>();
String label = null;
for (Iterator<EObject> it = aggrconResource.getAllContents(); it.hasNext();)
{
EObject eObject = it.next();
if (label == null)
{
label = get(eObject, "Contribution", "label");
if ("false".equals(get(eObject, "Contribution", "enabled")))
{
System.out.println("Disabled");
continue LOOP;
}
}
if ("false".equals(get(eObject, "repositories", "enabled")))
{
System.out.println("Disabled repository");
continue LOOP;
}
String location = get(eObject, "repositories", "location");
if (location != null)
{
String normalizedLocation = location.replaceAll("/$", "");
repository = URI
.createURI(normalizedLocation.contains("//repo.eclipse.org") ? normalizedLocation : normalizedLocation.replaceAll("^https:", "http:"));
}
else
{
for (String elementName : new String[] { "features", "bundles", "products" })
{
String iuID = get(eObject, elementName, "name");
if (iuID != null)
{
String versionRangeLiteral = get(eObject, elementName, "versionRange");
VersionRange versionRange = null;
try
{
versionRange = VersionRange.create(versionRangeLiteral);
}
catch (RuntimeException ex)
{
Pattern exactVersionPattern = Pattern.compile("\\[([^,]*)\\]");
Matcher matcher = exactVersionPattern.matcher(versionRangeLiteral);
if (matcher.matches())
{
Version version = Version.parseVersion(matcher.group(1));
versionRange = new VersionRange(version, true, version, true);
}
else
{
throw ex;
}
}
Requirement requirement = P2Factory.eINSTANCE.createRequirement(iuID, versionRange);
CollectionUtil.add(requirements, repository, requirement);
}
}
String contact = get(eObject, "contacts", "href");
if (contact != null)
{
Pattern emailPattern = Pattern.compile("email='([^']+)'");
Matcher matcher = emailPattern.matcher(contact);
if (matcher.find())
{
contacts.add(matcher.group(1));
}
}
}
}
String compositeName = URI.encodeSegment(aggrcon.trimFragment().toString(), false);
compositeName = compositeName.replace(":", "%3A");
composites.add(createAggrconComposite(outputLocation, label, aggrcon.toString().replace("/plain/", "/tree/").replace("#/$", ""), compositeName,
requirements, contacts));
}
return composites;
}
private URI createAggrconComposite(File outputLocation, String label, String aggrconHref, String aggrconName, Map<URI, Set<Requirement>> requirements,
Set<String> contacts) throws ProvisionException, OperationCanceledException, URISyntaxException
{
File compositeAggrconLocations = new File(outputLocation, "aggrcons");
compositeAggrconLocations.mkdirs();
File compositeAggrconLocation = new File(compositeAggrconLocations, aggrconName);
IOUtil.deleteBestEffort(compositeAggrconLocation);
Map<String, String> properties = new LinkedHashMap<>();
for (Map.Entry<URI, Set<Requirement>> entry : requirements.entrySet())
{
URI uri = entry.getKey();
StringBuilder value = new StringBuilder();
for (Requirement requirement : entry.getValue())
{
if (value.length() != 0)
{
value.append(';');
}
value.append(requirement.getName());
VersionRange versionRange = requirement.getVersionRange();
if (versionRange != null && !versionRange.equals(VersionRange.emptyRange))
{
value.append(' ');
value.append(versionRange);
}
}
properties.put(uri.toString(), value.toString());
}
properties.put("contacts", contacts.toString());
properties.put("aggrcon", aggrconHref);
java.net.URI locationURI = compositeAggrconLocation.toURI();
getMetadataRepositoryManager().createRepository(locationURI, label, IMetadataRepositoryManager.TYPE_COMPOSITE_REPOSITORY, properties);
properties.remove("contacts");
properties.remove("aggrcon");
for (Map.Entry<String, String> entry : properties.entrySet())
{
entry.setValue("");
}
getArtifactRepositoryManager().createRepository(locationURI, label, IArtifactRepositoryManager.TYPE_COMPOSITE_REPOSITORY, properties);
return URI.createURI(locationURI.toString());
}
private String get(EObject eObject, String elementName, String attributeName)
{
if (eObject instanceof AnyType)
{
AnyType anyType = (AnyType)eObject;
if (elementName.equals(anyType.eContainmentFeature().getName()))
{
FeatureMap anyAttribute = anyType.getAnyAttribute();
for (FeatureMap.Entry entry : anyAttribute)
{
if (attributeName.equals(entry.getEStructuralFeature().getName()))
{
return entry.getValue().toString();
}
}
}
}
return null;
}
private java.net.URI toInternalRepositoryLocation(URI uri) throws URISyntaxException
{
if (DOWNLOAD_ECLIPSE_ORG_AUTHORITY.equals(uri.authority()) && DOWNLOAD_ECLIPSE_ORG_FOLDER_EXISTS)
{
File file = DOWNLOAD_ECLIPSE_ORG_FOLDER;
for (String segment : uri.segments())
{
file = new File(file, segment);
}
boolean exists = file.exists();
if (verbose)
{
System.out.println("Redirecting '" + uri + "' to '" + file + "' success=" + exists);
}
if (exists)
{
return file.toURI();
}
}
java.net.URI location = new java.net.URI(uri.toString());
return location;
}
private URI toExternalRepositoryLocation(java.net.URI child)
{
String childLocation = child.toString();
String downloadEclipseOrgFolderLocation = DOWNLOAD_ECLIPSE_ORG_FOLDER_URI.toString();
if (childLocation.startsWith(downloadEclipseOrgFolderLocation))
{
URI.createURI(DOWNLOAD_ECLIPSE_ORG_SERVER_URI + childLocation.substring(DOWNLOAD_ECLIPSE_ORG_FOLDER_URI.length()));
}
URI uri = URI.createURI(child.toString());
if ("".equals(uri.lastSegment()))
{
uri = uri.trimSegments(1);
}
return uri;
}
private static File[] listSortedFiles(File folder)
{
File[] files = folder.listFiles();
final Comparator<String> comparator = CommonPlugin.INSTANCE.getComparator();
Arrays.sort(files, new Comparator<File>()
{
@Override
public int compare(File f1, File f2)
{
return comparator.compare(f1.getPath(), f2.getPath());
}
});
return files;
}
private static String toRelativePath(URI uri)
{
if (isAggrconRepositoryURI(uri))
{
String lastSegment = uri.lastSegment();
String decode = URI.decode(URI.decode(lastSegment));
return URI.createURI(decode).lastSegment();
}
StringBuilder result = new StringBuilder();
String authority = uri.authority();
if (!StringUtil.isEmpty(authority))
{
result.append(IOUtil.encodeFileName(authority));
}
String device = uri.device();
if (!StringUtil.isEmpty(device))
{
if (result.length() != 0)
{
result.append("/");
}
result.append(IOUtil.encodeFileName(device));
}
for (String segment : uri.segments())
{
if (!StringUtil.isEmpty(segment))
{
if (result.length() != 0)
{
result.append("/");
}
result.append(IOUtil.encodeFileName(segment));
}
}
return result.toString();
}
private static String toTestPackageName(URI uri)
{
if (isAggrconRepositoryURI(uri))
{
return toTestPackageName(URI.createURI(uri.lastSegment()));
}
StringBuilder result = new StringBuilder();
for (String segment : uri.segments())
{
if (!StringUtil.isEmpty(segment))
{
if (result.length() != 0)
{
result.append(".");
}
StringBuilder packageName = new StringBuilder();
for (char ch : segment.toCharArray())
{
if (packageName.length() == 0)
{
if (!Character.isJavaIdentifierStart(ch))
{
packageName.append('_');
}
}
if (Character.isJavaIdentifierPart(ch))
{
packageName.append(ch);
}
else
{
packageName.append('_');
}
}
result.append(packageName);
}
}
return result.toString();
}
private static TestSuite createTestSuite(File testsLocation, String fileName, String qualifiedClassName)
{
URI uri = URI.createFileURI(new File(testsLocation, fileName).toString());
Resource resource = Resource.Factory.Registry.INSTANCE.getFactory(uri, JUnitPackage.eCONTENT_TYPE).createResource(uri);
TestSuite testSuite = JUnitFactory.eINSTANCE.createTestSuite();
testSuite.setName(qualifiedClassName);
testSuite.setProperties(JUnitFactory.eINSTANCE.createPropertiesType());
testSuite.setTimestamp(System.currentTimeMillis());
resource.getContents().add(testSuite);
return testSuite;
}
private static TestCaseType createTestCase(TestSuite testSuite, String name)
{
TestCaseType testCase = JUnitFactory.eINSTANCE.createTestCaseType();
testCase.setClassName(testSuite.getName());
testCase.setName(name);
testSuite.getTestCases().add(testCase);
return testCase;
}
private static void addFailure(TestCaseType testCase, String message, String value)
{
ProblemType problemType = JUnitFactory.eINSTANCE.createProblemType();
problemType.setMessage(message);
problemType.setType(RepositoryIntegrityAnalyzer.class.getName());
problemType.setValue(message + "\n" + value);
testCase.setFailure(problemType);
}
private static void publish(File outputLocation, File publishLocation) throws IOException
{
File newPublishLocation = new File(publishLocation.toString() + ".new");
if (newPublishLocation.exists())
{
if (!IOUtil.deleteBestEffort(newPublishLocation))
{
throw new IOException("The location '" + newPublishLocation + "' cannot be deleted");
}
}
IOUtil.copyTree(outputLocation, newPublishLocation);
File oldPublishLocation = null;
if (publishLocation.exists())
{
oldPublishLocation = new File(publishLocation.toString() + ".old");
if (oldPublishLocation.exists())
{
if (!IOUtil.deleteBestEffort(oldPublishLocation))
{
throw new IOException("The location '" + oldPublishLocation + "' cannot be deleted");
}
}
if (!publishLocation.renameTo(oldPublishLocation))
{
throw new IOException("The location '" + publishLocation + "' cannot be renamed to '" + oldPublishLocation + "'");
}
}
if (!newPublishLocation.renameTo(publishLocation))
{
throw new IOException("The location '" + newPublishLocation + "' cannot be renamed to '" + publishLocation + "'");
}
if (oldPublishLocation != null)
{
IOUtil.deleteBestEffort(oldPublishLocation);
}
}
private static void createFolders(File folder) throws IOException
{
if (folder.exists())
{
if (!folder.isDirectory())
{
throw new IOException("The location '" + folder + "' already exists as a file");
}
}
else
{
if (!folder.mkdirs())
{
throw new IOException("The location '" + folder + "' cannot be created as a directory");
}
}
}
private void generateIndex(IndexReport indexReport, RepositoryIndex repositoryIndex, String reportSource, String reportBranding) throws IOException
{
if (verbose)
{
System.out.println("Generating report index for '" + indexReport.getFolder());
}
String result = repositoryIndex.generate(indexReport);
images.clear();
OutputStream out = null;
try
{
File outputLocation = indexReport.getFolder();
File index = new File(outputLocation, "index.html");
out = new FileOutputStream(index);
new PrintStream(out, false, "UTF-8").print(result);
File publishLocation = indexReport.getPublishLocation();
if (publishLocation != null)
{
IOUtil.copyFile(index, new File(publishLocation, "index.html"));
for (File file : outputLocation.listFiles())
{
String name = file.getName();
if (name.endsWith(".png"))
{
IOUtil.copyFile(file, new File(publishLocation, name));
}
}
}
}
finally
{
IOUtil.closeSilent(out);
}
for (IndexReport child : indexReport.getChildren())
{
generateIndex(child, repositoryIndex, reportSource, reportBranding);
}
}
private void emitReport(Map<String, String> allReports, Set<Report> visited, Report report, final File outputLocation, File testsLocation,
final RepositoryIndex repositoryIndexEmitter) throws IOException, InterruptedException
{
if (visited.add(report))
{
if (verbose)
{
System.out.println("Emmitting report for '" + report.getSiteURL() + "'");
}
String result = repositoryIndexEmitter.generate(report);
String relativeIndexURL = report.getRelativeIndexURL();
if (outputLocation == null)
{
System.out.println("---" + relativeIndexURL + "---");
System.out.println(result);
}
else
{
OutputStream out = null;
try
{
File reportOutputLocation = new File(outputLocation, relativeIndexURL);
out = new FileOutputStream(reportOutputLocation);
allReports.put(report.getSiteURL(), reportOutputLocation.toString());
new PrintStream(out, false, "UTF-8").print(result);
}
finally
{
IOUtil.closeSilent(out);
}
}
if (testsLocation != null)
{
URI siteURI = URI.createURI(report.getSiteURL());
String testPackageName = toTestPackageName(siteURI);
System.err.println("###" + testsLocation);
System.err.println("###>" + testPackageName);
boolean simple = report.isSimple();
TestSuite testSuite;
if (simple || isAggrconRepositoryURI(siteURI))
{
String qualifiedClassName = testPackageName + (simple ? ".Simple" : ".AggrCon");
testSuite = createTestSuite(testsLocation, "TEST-" + qualifiedClassName + ".xml", qualifiedClassName);
Set<IInstallableUnit> allIUs = report.getAllIUs();
Set<IInstallableUnit> badLicenseIUs = report.getBadLicenseIUs();
Set<IInstallableUnit> badProviderIUs = report.getBadProviderIUs();
Map<String, Set<IInstallableUnit>> featureProviders = report.getFeatureProviders();
Set<IInstallableUnit> brokenBrandingIUs = report.getBrokenBrandingIUs();
Map<List<Certificate>, Map<String, IInstallableUnit>> certificates = report.getCertificates();
Map<String, IInstallableUnit> unsigned = certificates.get(Collections.emptyList());
for (IInstallableUnit iu : allIUs)
{
if (iu.getId().endsWith(".feature.group"))
{
{
long start = System.currentTimeMillis();
TestCaseType testCase = createTestCase(testSuite, "validLicense_" + iu);
if (badLicenseIUs.contains(iu))
{
addFailure(testCase, "The feature IU '" + iu + "' does not have a valid license", siteURI.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
{
long start = System.currentTimeMillis();
TestCaseType testCase = createTestCase(testSuite, "validProvider_" + iu);
if (badProviderIUs.contains(iu))
{
StringBuilder message = new StringBuilder();
for (Map.Entry<String, Set<IInstallableUnit>> entry : featureProviders.entrySet())
{
if (entry.getValue().contains(iu))
{
message.append(entry.getKey()).append('\n');
break;
}
}
message.append(siteURI);
addFailure(testCase, "The feature IU '" + iu + "' does not valid provider", message.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
{
long start = System.currentTimeMillis();
TestCaseType testCase = createTestCase(testSuite, "validBranding_" + iu);
if (brokenBrandingIUs.contains(iu))
{
addFailure(testCase, "The feature IU '" + iu + "' has a broken branding image", siteURI.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
}
{
long start = System.currentTimeMillis();
Map<String, Boolean> iuArtifacts = report.getIUArtifacts(iu);
if (!iuArtifacts.isEmpty())
{
TestCaseType testCase = createTestCase(testSuite, "validSignedArtifacts_" + iu);
if (unsigned != null && unsigned.containsValue(iu))
{
StringBuilder message = new StringBuilder();
for (String artifact : iuArtifacts.keySet())
{
if (message.length() != 0)
{
message.append('\n');
}
message.append(siteURI).append('/').append(artifact);
}
addFailure(testCase, "The IU '" + iu + "' has unsigned artifacts", message.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
}
}
}
else
{
String qualifiedClassName = testPackageName + ".Composite";
testSuite = createTestSuite(testsLocation, "TEST-" + qualifiedClassName + ".xml", qualifiedClassName);
{
long start = System.currentTimeMillis();
TestCaseType testCase = createTestCase(testSuite, "validMetadataLocations");
String metadataXML = report.getMetadataXML();
if (metadataXML != null && metadataXML.contains("bad-absolute-location"))
{
addFailure(testCase, "The composite content XML contains an absolute URI referencing the same host", siteURI.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
{
long start = System.currentTimeMillis();
TestCaseType testCase = createTestCase(testSuite, "validArtifactLocations");
String artifactXML = report.getArtifactML();
if (artifactXML != null && artifactXML.contains("bad-absolute-location"))
{
addFailure(testCase, "The composite artifact XML contains an absolute URI referencing the same host", siteURI.toString());
}
long end = System.currentTimeMillis();
testCase.setTime((end - start) / 1000.0);
}
}
testSuite.summarize();
Diagnostic diagnostic = Diagnostician.INSTANCE.validate(testSuite);
if (diagnostic.getSeverity() != Diagnostic.OK)
{
System.err.println("###");
}
testSuite.eResource().save(null);
}
List<IUReport> iuReports = report.getIUReports();
if (!iuReports.isEmpty())
{
URI iuReportFolder = URI.createURI(relativeIndexURL).trimFileExtension();
new File(outputLocation, iuReportFolder.toString()).mkdir();
ExecutorService executor = getExecutor();
List<Future<Void>> futures = new ArrayList<>();
for (final IUReport iuReport : iuReports)
{
futures.add(executor.submit(new Callable<Void>()
{
@Override
public Void call() throws Exception
{
String iuResult = repositoryIndexEmitter.generate(iuReport);
String relativeIUReportURL = iuReport.getRelativeReportURL();
OutputStream out = null;
try
{
out = new FileOutputStream(new File(outputLocation, relativeIUReportURL));
new PrintStream(out, false, "UTF-8").print(iuResult);
}
finally
{
IOUtil.closeSilent(out);
}
return null;
}
}));
}
if (verbose)
{
System.out.println("Emmitting report IU details for '" + report.getSiteURL() + "'");
}
for (Future<Void> future : futures)
{
get(future);
}
}
for (Report childReport : report.getChildren())
{
emitReport(allReports, visited, childReport, outputLocation, testsLocation, repositoryIndexEmitter);
}
}
}
@Override
public void stop()
{
}
private Report.LicenseDetail getLicenseDetail(ILicense license, boolean demandCreate)
{
java.net.URI location = license.getLocation();
URI locationURI = location == null ? Report.NO_LICENSE_URI : URI.createURI(location.toString());
String uuid = license.getUUID();
Report.LicenseDetail licenseDetail = details.get(uuid);
if (licenseDetail == null && demandCreate)
{
licenseDetail = new Report.LicenseDetail(locationURI, license);
details.put(uuid, licenseDetail);
}
return licenseDetail;
}
private List<Report.LicenseDetail> getLicenses(IInstallableUnit installableUnit)
{
List<Report.LicenseDetail> result = new ArrayList<>();
Collection<ILicense> licenses = installableUnit.getLicenses(null);
if (licenses.isEmpty())
{
result.add(getLicenseDetail(Report.NO_LICENSE, true));
}
else
{
for (ILicense license : licenses)
{
result.add(getLicenseDetail(license, true));
}
}
return result;
}
private Set<IInstallableUnit> query(IMetadataRepository metadataRepository, IQuery<IInstallableUnit> query)
{
IQueryResult<IInstallableUnit> queryResult = metadataRepository.query(query, new NullProgressMonitor());
Set<IInstallableUnit> result = new TreeSet<>();
for (IInstallableUnit iu : P2Util.asIterable(queryResult))
{
result.add(iu);
}
return result;
}
public Report generateReport(final Report parentReport, final URI rootURI, final File rootOutputLocation, final URI uri, final File outputLocation,
final Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache, final File artifactCacheFolder, final String reportSource,
final String reportBranding) throws Exception
{
Report report = reports.get(uri);
if (report == null)
{
reports.put(uri, null);
final IMetadataRepository metadataRepository = loadMetadataRepository(getMetadataRepositoryManager(), uri);
IArtifactRepository loadedArtifactRepository;
try
{
loadedArtifactRepository = loadArtifactRepository(getArtifactRepositoryManager(), uri);
}
catch (ProvisionException exception)
{
loadedArtifactRepository = null;
}
final IArtifactRepository artifactRepository = loadedArtifactRepository;
final Set<IInstallableUnit> allIUs = getAllIUs(metadataRepository);
if (artifactRepository != null)
{
for (IInstallableUnit iu : query(metadataRepository, QueryUtil.createIUAnyQuery()))
{
for (IArtifactKey artifactKey : iu.getArtifacts())
{
getArtifacts(artifactKey, artifactRepository, artifactCache, artifactCacheFolder);
}
}
}
final Set<IInstallableUnit> productIUs = new TreeSet<>();
for (IInstallableUnit iu : allIUs)
{
if ("true".equals(iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_PRODUCT)))
{
productIUs.add(iu);
}
}
final Map<Report.LicenseDetail, Set<IInstallableUnit>> licenseIUs = new LinkedHashMap<>();
for (ILicense sua : Report.SUAS)
{
licenseIUs.put(getLicenseDetail(sua, true), new LinkedHashSet<IInstallableUnit>());
}
final Set<String> expectedDuplicates = new HashSet<>();
expectedDuplicates.add("a.jre.javase");
expectedDuplicates.add("config.a.jre.javase");
for (IInstallableUnit iu : allIUs)
{
if ("true".equals(iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_GROUP)))
{
CollectionUtil.addAll(licenseIUs, getLicenses(iu), iu);
Set<String> ids = new HashSet<>();
for (final IRequirement requirement : iu.getRequirements())
{
if (requirement instanceof IRequiredCapability)
{
IRequiredCapability requiredCapability = (IRequiredCapability)requirement;
String namespace = requiredCapability.getNamespace();
if (IInstallableUnit.NAMESPACE_IU_ID.equals(namespace))
{
String name = requiredCapability.getName();
if (!ids.add(name))
{
expectedDuplicates.add(name);
}
}
}
}
}
}
final Map<Report.LicenseDetail, Set<IInstallableUnit>> sortedLicenseIUs = new LinkedHashMap<>();
while (!licenseIUs.isEmpty())
{
Map.Entry<Report.LicenseDetail, Set<IInstallableUnit>> biggestEntry = null;
for (Map.Entry<Report.LicenseDetail, Set<IInstallableUnit>> entry : licenseIUs.entrySet())
{
if (biggestEntry == null)
{
biggestEntry = entry;
}
else if (biggestEntry.getValue().size() < entry.getValue().size())
{
biggestEntry = entry;
}
}
licenseIUs.remove(biggestEntry.getKey());
Set<IInstallableUnit> ius = biggestEntry.getValue();
if (ius.isEmpty())
{
// Omit the ones that are empty.
break;
}
TreeSet<IInstallableUnit> sortedLicenseIUValues = new TreeSet<>(NAME_VERSION_COMPARATOR);
sortedLicenseIUValues.addAll(biggestEntry.getValue());
sortedLicenseIUs.put(biggestEntry.getKey(), sortedLicenseIUValues);
}
final List<IInstallableUnit> featureIUs = new ArrayList<>();
for (IInstallableUnit featureIU : allIUs)
{
if (featureIU.getId().endsWith(Requirement.FEATURE_SUFFIX))
{
featureIUs.add(featureIU);
}
}
Collections.sort(featureIUs, NAME_VERSION_COMPARATOR);
final Map<IInstallableUnit, Future<URI>> brandingImages = new LinkedHashMap<>();
if (artifactRepository != null)
{
for (IInstallableUnit featureIU : featureIUs)
{
getBrandingImage(featureIU, metadataRepository, artifactRepository, brandingImages, artifactCache, artifactCacheFolder);
}
}
Map<IInstallableUnit, Map<File, Future<SignedContent>>> signedContentCache = new LinkedHashMap<>();
for (IInstallableUnit iu : allIUs)
{
getSignedContent(iu, artifactCache, signedContentCache);
}
Map<IInstallableUnit, Map<File, Set<PGPPublicKey>>> pgpSignedContentCache = new LinkedHashMap<>();
for (IInstallableUnit iu : allIUs)
{
getPGPSignedContent(iu, artifactCache, pgpSignedContentCache);
}
final Map<List<String>, IRequirement> requiredCapabilities = new HashMap<>();
Map<IRequirement, Future<Set<IInstallableUnit>>> futures = new HashMap<>();
Map<IRequirement, Set<IInstallableUnit>> requiringIUs = new HashMap<>();
for (IInstallableUnit iu : allIUs)
{
for (final IRequirement requirement : iu.getRequirements())
{
CollectionUtil.add(requiringIUs, requirement, iu);
Future<Set<IInstallableUnit>> future = futures.get(requirement);
if (future == null)
{
IMatchExpression<IInstallableUnit> match = requirement.getMatches();
if (RequiredCapability.isVersionRangeRequirement(match))
{
List<String> key = new ArrayList<>(3);
key.add(RequiredCapability.extractNamespace(match));
key.add(RequiredCapability.extractName(match));
key.add(RequiredCapability.extractRange(match).toString());
requiredCapabilities.put(key, requirement);
}
futures.put(requirement, getExecutor().submit(new Callable<Set<IInstallableUnit>>()
{
@Override
public Set<IInstallableUnit> call() throws Exception
{
return query(metadataRepository, QueryUtil.createMatchQuery(requirement.getMatches()));
}
}));
}
}
}
final Map<List<String>, IProvidedCapability> allProvidedCapabilities = new HashMap<>();
final Map<IRequirement, Set<IInstallableUnit>> resolvedRequirements = new HashMap<>();
final Map<IProvidedCapability, Set<IInstallableUnit>> resolvedCapabilities = new HashMap<>();
final Map<IProvidedCapability, Set<IRequirement>> capabilityResolutions = new HashMap<>();
final Map<IRequirement, Set<IProvidedCapability>> requirementResolutions = new HashMap<>();
for (Map.Entry<IRequirement, Future<Set<IInstallableUnit>>> entry : futures.entrySet())
{
IRequirement requirement = entry.getKey();
Set<IInstallableUnit> ius = get(entry.getValue());
resolvedRequirements.put(requirement, ius);
if (requirement instanceof IRequiredCapability)
{
IRequiredCapability requiredCapability = (IRequiredCapability)requirement;
String requirementNamespace = requiredCapability.getNamespace();
String requirementName = requiredCapability.getName();
VersionRange range = requiredCapability.getRange();
for (IInstallableUnit iu : ius)
{
Collection<IProvidedCapability> providedCapabilities = iu.getProvidedCapabilities();
for (IProvidedCapability providedCapability : providedCapabilities)
{
String namespace = providedCapability.getNamespace();
String name = providedCapability.getName();
Version version = providedCapability.getVersion();
List<String> key = new ArrayList<>();
key.add(namespace);
key.add(name);
key.add(version.toString());
allProvidedCapabilities.put(key, providedCapability);
if (ObjectUtil.equals(requirementNamespace, namespace) && ObjectUtil.equals(requirementName, name) && range.isIncluded(version))
{
CollectionUtil.add(capabilityResolutions, providedCapability, requirement);
CollectionUtil.add(requirementResolutions, requirement, providedCapability);
Set<IInstallableUnit> resolvedIUs = requiringIUs.get(requirement);
if (resolvedIUs != null)
{
for (IInstallableUnit resolvedIU : resolvedIUs)
{
CollectionUtil.add(resolvedCapabilities, providedCapability, resolvedIU);
}
}
}
}
}
}
}
final Map<IInstallableUnit, Set<File>> iuFiles = new TreeMap<>();
final Map<File, SignedContent> fileSignedContents = new TreeMap<>();
final Map<File, Set<PGPPublicKey>> filePGPSignedContents = new TreeMap<>();
final Map<File, List<String>> localFileIndices = new TreeMap<>();
final Set<IInstallableUnit> classContainingIUs = new TreeSet<>();
final Map<String, Set<Version>> iuIDVersions = new TreeMap<>();
for (IInstallableUnit iu : allIUs)
{
Set<File> files = new LinkedHashSet<>();
for (Map.Entry<File, Future<SignedContent>> entry : signedContentCache.get(iu).entrySet())
{
File file = entry.getKey();
files.add(file);
SignedContent signedContent = get(entry.getValue());
fileSignedContents.put(file, signedContent);
filePGPSignedContents.put(file, pgpSignedContentCache.get(iu).get(file));
List<String> index = get(getIndex(file));
localFileIndices.put(file, index);
for (String string : index)
{
if (string.endsWith(".class"))
{
classContainingIUs.add(iu);
break;
}
}
}
iuFiles.put(iu, files);
CollectionUtil.add(iuIDVersions, iu.getId(), iu.getVersion());
}
final List<Report> childReports = new ArrayList<>();
class MyReport extends Report
{
@SuppressWarnings("unused")
public void getArtifacts()
{
Map<File, Set<IInstallableUnit>> artifacts = new TreeMap<>();
for (IInstallableUnit iu : allIUs)
{
for (IArtifactKey artifactKey : iu.getArtifacts())
{
Future<Map<IArtifactDescriptor, File>> artifactCacheFuture = artifactCache.get(artifactKey);
if (artifactCacheFuture != null)
{
for (File file : get(artifactCacheFuture).values())
{
CollectionUtil.add(artifacts, file, iu);
}
}
}
}
}
private Map<String, String> breadcrumbs;
@Override
public Map<String, String> getBreadcrumbs()
{
if (breadcrumbs == null)
{
Map<String, String> result = new LinkedHashMap<>();
String rootFolderName = rootOutputLocation.getName();
result.put(rootFolderName, null);
int segmentCount = uri.segmentCount();
URI relativeURI = URI.createURI(toRelativePath(uri));
int relativeSegmentCount = relativeURI.segmentCount();
int extraSegmentCount = isAggrconRepositoryURI(uri) ? 1 : relativeSegmentCount - segmentCount;
int depth = URI.createURI(toRelativePath(rootURI)).segmentCount();
for (int i = 0; i < relativeSegmentCount; ++i)
{
String segment = relativeURI.segment(i);
URI href = null;
URI parentURI = uri.trimSegments(relativeSegmentCount - i - extraSegmentCount);
Report parentReport = reports.get(parentURI);
if (parentReport == null)
{
for (int j = i + extraSegmentCount; j < depth; ++j)
{
href = href == null ? URI.createURI("..") : href.appendSegment("..");
}
href = href == null ? URI.createURI("index.html") : href.appendSegment("index.html");
}
else if (parentReport != this)
{
for (int j = i + extraSegmentCount; j < depth; ++j)
{
href = href == null ? URI.createURI("..") : href.appendSegment("..");
}
String relativeIndexURL = parentReport.getRelativeIndexURL();
href = href == null ? URI.createURI(relativeIndexURL) : href.appendSegment(relativeIndexURL);
result.put(segment, href.toString());
}
result.put(segment, href == null ? null : href.toString());
if (i == 0)
{
result.put(rootFolderName, href == null ? "../index.html" : "../" + href);
}
}
breadcrumbs = result;
}
return breadcrumbs;
}
@Override
public boolean isSimple()
{
return !(metadataRepository instanceof ICompositeRepository<?>);
}
@Override
public boolean isRoot()
{
return rootURI.equals(uri);
}
@Override
public String getReportSource()
{
return reportSource;
}
@Override
public String getReportBrandingImage()
{
return getImage(URI.createURI(reportBranding), outputLocation);
}
@Override
public boolean hasBrandingImage(IInstallableUnit iu)
{
String brandingImage = getBrandingImage(iu);
return !brandingImage.equals(getWarningImage(outputLocation)) && !brandingImage.equals(getErrorImage());
}
@Override
public boolean hasBrokenBrandingImage(IInstallableUnit iu)
{
String brandingImage = getBrandingImage(iu);
return brandingImage.equals(getErrorImage());
}
@Override
public String getBrandingImage(IInstallableUnit iu)
{
Future<URI> brandingImage = brandingImages.get(iu);
if (brandingImage != null)
{
try
{
URI brandingImageURI = brandingImage.get();
if (brandingImageURI != null)
{
return getImage(brandingImageURI, outputLocation);
}
return getWarningImage(outputLocation);
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
return null;
}
@Override
public Map<String, Set<IInstallableUnit>> getFeatureProviders()
{
Map<String, Set<IInstallableUnit>> result = new TreeMap<>();
for (IInstallableUnit iu : featureIUs)
{
String provider = iu.getProperty(IInstallableUnit.PROP_PROVIDER, null);
CollectionUtil.add(result, String.valueOf(provider), iu);
}
return result;
}
@Override
public Set<String> getBrandingImages(Collection<IInstallableUnit> ius)
{
Set<String> result = new LinkedHashSet<>();
for (IInstallableUnit iu : ius)
{
result.add(getBrandingImage(iu));
}
String image = getWarningImage(outputLocation);
if (result.size() > 1)
{
result.remove(image);
}
return result;
}
@Override
public String getSignedImage(boolean signed)
{
return getImage("org.eclipse.ui", signed ? "icons/full/obj16/signed_yes_tbl.png" : "icons/full/obj16/signed_no_tbl.png", outputLocation);
}
@Override
public Map<String, Set<Version>> getIUVersions()
{
return iuIDVersions;
}
@Override
public Set<IInstallableUnit> getClassContainingIUs()
{
return classContainingIUs;
}
private Set<IInstallableUnit> unsignedIUs;
@Override
public Set<IInstallableUnit> getUnsignedIUs()
{
if (unsignedIUs == null)
{
unsignedIUs = new TreeSet<>();
for (IInstallableUnit iu : allIUs)
{
Map<String, Boolean> iuArtifacts = getIUArtifacts(iu);
if (iuArtifacts.containsValue(Boolean.FALSE))
{
unsignedIUs.add(iu);
}
}
}
return unsignedIUs;
}
private Set<IInstallableUnit> badProviderIUs;
@Override
public Set<IInstallableUnit> getBadProviderIUs()
{
if (badProviderIUs == null)
{
badProviderIUs = new TreeSet<>();
Map<String, Set<IInstallableUnit>> featureProviders = getFeatureProviders();
for (Map.Entry<String, Set<IInstallableUnit>> entry : featureProviders.entrySet())
{
String provider = entry.getKey();
if (provider == null || !provider.toLowerCase().contains("eclipse"))
{
badProviderIUs.addAll(entry.getValue());
}
}
}
return badProviderIUs;
}
private Set<IInstallableUnit> badLicenseIUs;
@Override
public Set<IInstallableUnit> getBadLicenseIUs()
{
if (badLicenseIUs == null)
{
badLicenseIUs = new TreeSet<>();
Map<LicenseDetail, Set<IInstallableUnit>> licenses = getLicenses();
for (Map.Entry<LicenseDetail, Set<IInstallableUnit>> entry : licenses.entrySet())
{
if (!entry.getKey().isSUA())
{
badLicenseIUs.addAll(entry.getValue());
}
}
}
return badLicenseIUs;
}
private Set<IInstallableUnit> brokenBrandingIUs;
@Override
public Set<IInstallableUnit> getBrokenBrandingIUs()
{
if (brokenBrandingIUs == null)
{
brokenBrandingIUs = new TreeSet<>();
for (IInstallableUnit iu : getFeatureIUs())
{
if (hasBrokenBrandingImage(iu))
{
brokenBrandingIUs.add(iu);
}
}
}
return brokenBrandingIUs;
}
@Override
public Map<String, Boolean> getIUArtifacts(IInstallableUnit iu)
{
Map<String, Boolean> result = new TreeMap<>();
Set<File> files = iuFiles.get(iu);
for (File file : files)
{
SignedContent signedContent = fileSignedContents.get(file);
int prefixLength = artifactCacheFolder.toString().length() + 1;
String path = file.toString().substring(prefixLength).replace('\\', '/');
Set<PGPPublicKey> keys = filePGPSignedContents.get(file);
result.put(path, signedContent == null || path.startsWith("binary/") ? null : signedContent.isSigned() || keys != null && !keys.isEmpty());
}
return result;
}
@Override
public String getRepositoryURL(String artifact)
{
for (Future<Map<IArtifactDescriptor, File>> future : artifactCache.values())
{
Map<IArtifactDescriptor, File> artifactFiles = get(future);
for (Map.Entry<IArtifactDescriptor, File> entry : artifactFiles.entrySet())
{
File file = entry.getValue();
String uriPath = file.toURI().toString();
if (uriPath.endsWith(artifact))
{
String location = entry.getKey().getRepository().getLocation().toString();
return location.replaceAll("/$", "");
}
}
}
throw new IllegalStateException();
}
@Override
public List<String> getArtifactStatus(String artifact)
{
for (Future<Map<IArtifactDescriptor, File>> future : artifactCache.values())
{
Map<IArtifactDescriptor, File> artifactFiles = get(future);
for (Map.Entry<IArtifactDescriptor, File> entry : artifactFiles.entrySet())
{
File file = entry.getValue();
String uriPath = file.toURI().toString();
if (uriPath.endsWith(artifact))
{
URI statusFile = URI.createURI(uriPath + ".processed.fail");
if (URIConverter.INSTANCE.exists(statusFile, Collections.emptyMap()))
{
try
{
return IOUtil.readLines(URIConverter.INSTANCE.createInputStream(statusFile), null);
}
catch (IOException ex)
{
}
}
statusFile = URI.createURI(uriPath + ".fail");
if (URIConverter.INSTANCE.exists(statusFile, Collections.emptyMap()))
{
try
{
return IOUtil.readLines(URIConverter.INSTANCE.createInputStream(statusFile), null);
}
catch (IOException ex)
{
}
}
}
}
}
return Collections.emptyList();
}
@Override
public boolean isExpired(Certificate certificate)
{
X509Certificate x509Certificate = (X509Certificate)certificate;
return new Date().after(x509Certificate.getNotAfter());
}
@Override
public Map<String, String> getCertificateComponents(Certificate certificate)
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'-'MM'-'dd");
X509Certificate x509Certificate = (X509Certificate)certificate;
String notBefore = dateFormat.format(x509Certificate.getNotBefore());
String notAfter = dateFormat.format(x509Certificate.getNotAfter());
X500Principal subjectX500Principal = x509Certificate.getSubjectX500Principal();
String name = subjectX500Principal.getName();
Pattern namePattern = Pattern.compile("([A-Za-z]+)=(([^,\\\\]|\\\\,)+),");
Matcher matcher = namePattern.matcher(name);
Map<String, String> components = new LinkedHashMap<>();
while (matcher.find())
{
components.put(matcher.group(1), matcher.group(2).replaceAll("\\\\", ""));
}
components.put("from", notBefore);
components.put("to", notAfter);
return components;
}
@Override
public Set<List<Certificate>> getCertificates(IInstallableUnit iu)
{
Set<List<Certificate>> result = new TreeSet<>(CERTIFICATE_COMPARATOR);
for (Map.Entry<List<Certificate>, Map<String, IInstallableUnit>> entry : getCertificates().entrySet())
{
if (entry.getValue().values().contains(iu))
{
result.add(entry.getKey());
}
}
return result;
}
private Map<List<Certificate>, Map<String, IInstallableUnit>> certificates;
@Override
public Map<List<Certificate>, Map<String, IInstallableUnit>> getCertificates()
{
if (certificates == null)
{
int prefixLength = artifactCacheFolder.toString().length() + 1;
certificates = new TreeMap<>(CERTIFICATE_COMPARATOR);
for (Map.Entry<IInstallableUnit, Set<File>> entry : iuFiles.entrySet())
{
IInstallableUnit iu = entry.getKey();
Set<File> files = entry.getValue();
for (File file : files)
{
String path = file.toString().substring(prefixLength).replace('\\', '/');
if (!path.startsWith("binary/"))
{
SignedContent signedContent = fileSignedContents.get(file);
if (signedContent != null && signedContent.isSigned())
{
SignerInfo[] signerInfos = signedContent.getSignerInfos();
for (SignerInfo signerInfo : signerInfos)
{
Certificate[] certificateChain = signerInfo.getCertificateChain();
List<Certificate> certificateList = Arrays.asList(certificateChain);
Map<String, IInstallableUnit> artifacts = certificates.get(certificateList);
if (artifacts == null)
{
artifacts = new TreeMap<>();
certificates.put(certificateList, artifacts);
}
artifacts.put(path, iu);
}
}
else if (getPGPKeys(file).isEmpty())
{
Map<String, IInstallableUnit> artifacts = certificates.get(Collections.emptyList());
if (artifacts == null)
{
artifacts = new TreeMap<>();
certificates.put(Collections.<Certificate> emptyList(), artifacts);
}
artifacts.put(path, iu);
}
}
}
}
}
return certificates;
}
private Set<PGPPublicKey> getPGPKeys(File file)
{
File pgpKeyFile = new File(file + ".asc");
if (pgpKeyFile.isFile())
{
try
{
Set<PGPPublicKey> pgpPubliKeys = PGPPublicKeyStore.readPublicKeys(IOUtil.readUTF8(pgpKeyFile));
return pgpPubliKeys;
}
catch (Exception ex)
{
System.err.println("### bad keys found " + file);
}
}
return Set.of();
}
@Override
public String getKeyServerURL(PGPPublicKey key)
{
return "https://keyserver.ubuntu.com/pks/lookup?search=0x" + PGPPublicKeyService.toHexFingerprint(key) + "&fingerprint=on&op=index";
}
@Override
public Set<PGPPublicKey> getPGPKeys(IInstallableUnit iu)
{
Set<PGPPublicKey> result = new TreeSet<>(PGP_COMPARATOR);
for (Map.Entry<PGPPublicKey, Map<String, IInstallableUnit>> entry : getPGPKeys().entrySet())
{
if (entry.getValue().values().contains(iu))
{
result.add(entry.getKey());
}
}
return result;
}
private Map<PGPPublicKey, Map<String, IInstallableUnit>> pgpKeys;
@Override
public Map<PGPPublicKey, Map<String, IInstallableUnit>> getPGPKeys()
{
if (pgpKeys == null)
{
pgpKeys = new TreeMap<>(PGP_COMPARATOR);
int prefixLength = artifactCacheFolder.toString().length() + 1;
for (Map.Entry<IInstallableUnit, Set<File>> entry : iuFiles.entrySet())
{
IInstallableUnit iu = entry.getKey();
Set<File> files = entry.getValue();
for (File file : files)
{
for (PGPPublicKey pgpPublicKey : getPGPKeys(file))
{
Map<String, IInstallableUnit> artifacts = pgpKeys.get(pgpPublicKey);
if (artifacts == null)
{
artifacts = new TreeMap<>();
pgpKeys.put(pgpPublicKey, artifacts);
}
String path = file.toString().substring(prefixLength).replace('\\', '/');
artifacts.put(path, iu);
}
}
}
}
return pgpKeys;
}
@Override
public List<String> getXML(final IInstallableUnit iu, Map<String, String> replacements)
{
getLicenses(iu);
if (Boolean.FALSE)
{
Collection<IRequirement> requirements = iu.getRequirements();
final Map<List<String>, IRequirement> requiredCapabilities = new HashMap<>();
for (IRequirement requirement : requirements)
{
IMatchExpression<IInstallableUnit> match = requirement.getMatches();
if (RequiredCapability.isVersionRangeRequirement(match))
{
List<String> key = new ArrayList<>(3);
key.add(RequiredCapability.extractNamespace(match));
key.add(RequiredCapability.extractName(match));
key.add(RequiredCapability.extractRange(match).toString());
requiredCapabilities.put(key, requirement);
}
}
}
final Map<String, String> ids = new HashMap<>();
ValueHandler valueHandler = new InstallableUnitWriter.ValueHandler()
{
private String uuid;
private String namespace;
private String name;
private String handleLicense(String content)
{
String plainContent = new InstallableUnitWriter().expandEntities(content);
ILicense license = MetadataFactory.createLicense(null, plainContent);
LicenseDetail licenseDetail = getLicenseDetail(license, false);
if (licenseDetail != null)
{
return licenseDetail.getUUID();
}
return null;
}
@Override
public String handleElementContent(List<String> elementNames, String elementContent)
{
if (XMLConstants.LICENSE_ELEMENT.equals(getCurrentElementName(elementNames)))
{
String licenseReplacement = handleLicense(elementContent);
if (licenseReplacement != null)
{
return licenseReplacement;
}
}
return super.handleElementContent(elementNames, elementContent);
}
@Override
public void startElement(List<String> elementNames, String uuid)
{
this.uuid = uuid;
}
@Override
public String handleAttributeValue(List<String> elementNames, String attributeName, String attributeValue)
{
String elementName = getCurrentElementName(elementNames);
if (XMLConstants.PROPERTY_ELEMENT.equals(elementName))
{
if (XMLConstants.PROPERTY_VALUE_ATTRIBUTE.equals(attributeName) && attributeValue.contains("&#xA;"))
{
String licenseReplacement = handleLicense(attributeValue);
if (licenseReplacement != null)
{
return licenseReplacement;
}
}
}
else if (XMLConstants.PROVIDED_CAPABILITY_ELEMENT.equals(elementName))
{
if (XMLConstants.NAMESPACE_ATTRIBUTE.equals(attributeName))
{
namespace = attributeValue;
}
else if (XMLConstants.NAME_ATTRIBUTE.equals(attributeName))
{
name = attributeValue;
}
else if (XMLConstants.VERSION_ATTRIBUTE.equals(attributeName))
{
List<String> key = new ArrayList<>();
key.add(namespace);
key.add(name);
key.add(attributeValue);
IProvidedCapability providedCapability = allProvidedCapabilities.get(key);
if (providedCapability != null)
{
ids.put(uuid, getProvidedCapabilityID(providedCapability));
}
Set<IInstallableUnit> matchingIUs = resolvedCapabilities.get(providedCapability);
if (matchingIUs == null || matchingIUs.isEmpty())
{
return "<span class=\"unused-capability\">" + attributeValue + "</span>";
}
StringBuilder links = new StringBuilder();
String id = "_" + EcoreUtil.generateUUID();
links.append(" <button id=\"" + id
+ "_arrows\" style=\"font-size: 70%; bottom-margin: 1pt; \" class=\"orange bb xml-links_button\" onclick=\"expand_collapse_inline_block('"
+ id + "');\">&#x25B7;</button>");
links.append("<span id=\"" + id + "\" class=\"xml-links\" style=\"display: none; margin-top: 0.2ex; vertical-align : top;\">");
for (IInstallableUnit iu : new TreeSet<>(matchingIUs))
{
links.append(" <a href=\"");
links.append(getIUID(iu));
links.append(".html");
HashSet<IRequirement> requirements = new HashSet<>(iu.getRequirements());
requirements.retainAll(capabilityResolutions.get(providedCapability));
if (!requirements.isEmpty())
{
links.append('#');
links.append(getRequirementID(requirements.iterator().next()));
}
links.append('"');
links.append(">\u27a6");
links.append(iu.getId());
links.append(" ");
links.append(iu.getVersion());
links.append("</a><br/>");
}
links.append("</span>");
return "<span class=\"used-capability\">" + attributeValue + links + "</span>";
}
}
else if (XMLConstants.REQUIREMENT_ELEMENT.equals(elementName))
{
if (XMLConstants.NAMESPACE_ATTRIBUTE.equals(attributeName))
{
namespace = attributeValue;
}
else if (XMLConstants.NAME_ATTRIBUTE.equals(attributeName))
{
name = attributeValue;
}
else if (XMLConstants.VERSION_RANGE_ATTRIBUTE.equals(attributeName))
{
List<String> key = new ArrayList<>();
key.add(namespace);
key.add(name);
key.add(attributeValue);
IRequirement requirement = requiredCapabilities.get(key);
if (requirement != null)
{
ids.put(uuid, getRequirementID(requirement));
}
Set<IInstallableUnit> matchingIUs = resolvedRequirements.get(requirement);
if (matchingIUs == null || matchingIUs.isEmpty())
{
return "<span class=\"unresolved-requirement\">" + attributeValue + "</span>";
}
String requirementName = "";
if (requirement instanceof IRequiredCapability)
{
requirementName = ((IRequiredCapability)requirement).getName();
}
StringBuilder links = new StringBuilder();
String id = "_" + EcoreUtil.generateUUID();
links.append(" <button id=\"" + id
+ "_arrows\" style=\"font-size: 70%; bottom-marin: 1pt;\" class=\"orange bb xml-links_button\" onclick=\"expand_collapse_inline_block('"
+ id + "');\">&#x25B7;</button>");
links.append("<span id=\"" + id + "\" class=\"xml-links\" style=\"display: none; margin-top: 0.2ex; vertical-align : top;\">");
for (IInstallableUnit iu : new TreeSet<>(matchingIUs))
{
links.append(" <a href=\"");
links.append(getIUID(iu));
links.append(".html");
HashSet<IProvidedCapability> providedCapabilities = new HashSet<>(iu.getProvidedCapabilities());
providedCapabilities.retainAll(requirementResolutions.get(requirement));
if (!providedCapabilities.isEmpty())
{
links.append('#');
links.append(getProvidedCapabilityID(providedCapabilities.iterator().next()));
}
links.append('"');
links.append(">\u27a5");
String iuID = iu.getId();
if (!requirementName.equals(iuID))
{
links.append(iuID);
links.append(' ');
}
links.append(iu.getVersion());
links.append("</a><br/>");
}
links.append("</span>");
ids.put(uuid, getRequirementID(requirement));
return "<span class=\"resolved-requirement\">" + attributeValue + links + "</span>";
}
}
return super.handleAttributeValue(elementNames, attributeName, attributeValue);
}
};
String xml = new InstallableUnitWriter().toHTML(iu, valueHandler);
if (replacements != null)
{
for (Map.Entry<String, String> entry : replacements.entrySet())
{
xml = xml.replace(entry.getKey(), entry.getValue());
}
}
StringBuffer result = new StringBuffer();
Matcher matcher = Pattern.compile("id=\"([^\"]+)\"").matcher(xml);
while (matcher.find())
{
String id = matcher.group(1);
String replacement = ids.get(id);
if (replacement != null)
{
matcher.appendReplacement(result, Matcher.quoteReplacement("id=\"" + replacement + '"'));
}
}
matcher.appendTail(result);
return StringUtil.explode(result.toString(), "\n");
}
@Override
public String getErrorImage()
{
return RepositoryIntegrityAnalyzer.this.getErrorImage(outputLocation);
}
@Override
public String getHelpLink()
{
return isAggrconRepository(metadataRepository) ? "https://wiki.eclipse.org/Oomph_Repository_Analyzer#Simultaneous_Release"
: "https://wiki.eclipse.org/Oomph_Repository_Analyzer#Update_Site_Pages";
}
@Override
public String getHelpImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/bundles/org.eclipse.jface/icons/full/help@2x.png"),
outputLocation);
}
@Override
public String getHelpText()
{
return isAggrconRepository(metadataRepository) ? "filtered aggrcon index" : "update site index";
}
@Override
public Report getParent()
{
return parentReport;
}
@Override
public List<Report> getChildren()
{
return childReports;
}
@Override
public Map<String, String> getNavigation()
{
Map<String, String> result = new LinkedHashMap<>();
for (Report report : reports.values())
{
String title = report.getTitle(true);
if (report == this)
{
title += '@';
}
result.put(report.getRelativeIndexURL(), title);
}
return result;
}
@Override
public String getSiteURL()
{
return metadataRepository.getLocation().toString();
}
private String getXML(CompositeRepositoryState state, String type)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
new CompositeRepositoryIO().write(state, out, type);
final String siteHost = URI.createURI(getSiteURL()).host();
ValueHandler valueHandler = new ValueHandler()
{
@Override
public String handleAttributeValue(List<String> elementNames, String attributeName, String attributeValue)
{
if ("location".equals(attributeName))
{
URI uri = URI.createURI(attributeValue);
String host = uri.host();
if (host != null && host.equals(siteHost))
{
return "<span class=\"bad-absolute-location\">" + toHref(attributeValue) + "</span>";
}
}
return super.handleAttributeValue(elementNames, toHref(attributeName), toHref(attributeValue));
}
private String toHref(String value)
{
return value.startsWith("http://") || value.startsWith("https://") ? "<a href=\"" + value + "\"/>" + value + "</a>" : value;
}
};
InstallableUnitWriter.HTMLResource htmlResource = new InstallableUnitWriter.HTMLResource(valueHandler);
try
{
htmlResource.load(new ByteArrayInputStream(out.toByteArray()), null);
out.reset();
XMLTypeDocumentRoot documentRoot = (XMLTypeDocumentRoot)htmlResource.getContents().get(0);
FeatureMap mixed = documentRoot.getMixed();
for (Iterator<FeatureMap.Entry> it = mixed.iterator(); it.hasNext();)
{
FeatureMap.Entry entry = it.next();
if (FeatureMapUtil.isProcessingInstruction(entry))
{
it.remove();
}
}
htmlResource.save(out, null);
return new String(out.toByteArray(), "UTF-8");
}
catch (IOException ex)
{
return null;
}
}
@Override
public String getMetadataXML()
{
if (metadataRepository instanceof CompositeMetadataRepository)
{
CompositeMetadataRepository compositeMetadataRepository = (CompositeMetadataRepository)metadataRepository;
return getXML(compositeMetadataRepository.toState(), CompositeArtifactRepository.PI_REPOSITORY_TYPE);
}
return null;
}
@Override
public String getArtifactML()
{
if (artifactRepository instanceof CompositeArtifactRepository)
{
CompositeArtifactRepository compositeArtifactRepository = (CompositeArtifactRepository)artifactRepository;
return getXML(compositeArtifactRepository.toState(), CompositeArtifactRepository.PI_REPOSITORY_TYPE);
}
return null;
}
@Override
public Map<Report.LicenseDetail, Set<IInstallableUnit>> getLicenses()
{
return sortedLicenseIUs;
}
@Override
public String getTitle()
{
String name = metadataRepository.getName();
return name.isEmpty() ? uri.lastSegment() : name;
}
@Override
public String getTitle(boolean narrow)
{
String name = metadataRepository.getName();
if (StringUtil.isEmpty(name))
{
name = "<span style=\"color: FireBrick;\">Unnamed Repository</span>";
}
if (aggregator)
{
return name;
}
String repoIdentifier = uri.lastSegment();
return name + (narrow ? "<br style=\"line-height: 4ex;\"/>" : " ") + "<span style=\"color: DarkOliveGreen;\">" + repoIdentifier + "</span>";
}
@Override
public String getDate()
{
String date = "unknown";
Map<String, String> properties = metadataRepository.getProperties();
String timestamp = properties.get(IRepository.PROP_TIMESTAMP);
if (timestamp != null)
{
try
{
long time = Long.parseLong(timestamp);
date = new SimpleDateFormat("yyyy'-'MM'-'dd' at 'HH':'mm ").format(new Date(time));
}
catch (RuntimeException ex)
{
//$FALL-THROUGH$
}
}
return date;
}
@Override
public List<String> getFeatures(Iterable<IInstallableUnit> features)
{
List<String> result = new ArrayList<>();
for (IInstallableUnit iu : features)
{
String name = getNameAndVersion(iu);
if (!result.contains(name))
{
result.add(name);
}
}
Collections.sort(result, CommonPlugin.INSTANCE.getComparator());
return result;
}
@Override
public List<String> getFeatures()
{
return getFeatures(getFeatureIUs());
}
@Override
public List<IInstallableUnit> getFeatureIUs()
{
return featureIUs;
}
@Override
public List<LicenseDetail> getLicenses(IInstallableUnit iu)
{
if ("true".equals(iu.getProperty(QueryUtil.PROP_TYPE_GROUP)))
{
return RepositoryIntegrityAnalyzer.this.getLicenses(iu);
}
return null;
}
@Override
public Set<IInstallableUnit> getProducts()
{
return productIUs;
}
@Override
public boolean isDuplicationExpected(String id)
{
return expectedDuplicates.contains(id);
}
@Override
public Set<IInstallableUnit> getAllIUs()
{
return allIUs;
}
@Override
public Set<IInstallableUnit> getResolvedRequirements(IInstallableUnit iu)
{
Set<IInstallableUnit> result = new TreeSet<>();
for (IRequirement requirement : iu.getRequirements())
{
Set<IInstallableUnit> ius = resolvedRequirements.get(requirement);
if (ius != null)
{
result.addAll(ius);
}
}
return result;
}
@Override
public String getArtifactImage(String artifact)
{
if (artifact.startsWith("binary"))
{
return getBinaryImage();
}
if (artifact.endsWith(".jar"))
{
return getJarImage();
}
if (artifact.endsWith(".pack.gz"))
{
return getPackGZImage();
}
return null;
}
@Override
public String getArtifactSize(String artifact)
{
long length = new File(artifactCacheFolder, artifact).length();
return format(length);
}
public String getBinaryImage()
{
return getImage(
URI.createURI("https://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/bundles/org.eclipse.ui.ide/icons/full/etool16/build_exec@2x.png"),
outputLocation);
}
public String getJarImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org.eclipse.jdt.ui/icons/full/etool16/exportjar_wiz@2x.png"),
outputLocation);
}
public String getPackGZImage()
{
return getImage(
URI.createURI(
"https://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/bundles/org.eclipse.ui.ide/icons/full/etool16/exportzip_wiz@2x.png"),
outputLocation);
}
@Override
public String getIUImage(IInstallableUnit iu)
{
if (isCategory(iu))
{
return getCategoryImage();
}
if (isProduct(iu))
{
return getProductImage();
}
if (isGroup(iu))
{
return getFeatureImage();
}
for (IProvidedCapability providedCapability : iu.getProvidedCapabilities())
{
if (PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE.equals(providedCapability.getNamespace()))
{
return getPluginImage();
}
}
for (IRequirement requirement : iu.getRequirements())
{
IMatchExpression<IInstallableUnit> match = requirement.getMatches();
if (RequiredCapability.isVersionRangeRequirement(match)
&& PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE.equals(RequiredCapability.extractNamespace(match)))
{
return getPluginImage();
}
}
return getBundleImage();
}
@Override
public String getLicenseImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/license_obj@2x.png"),
outputLocation);
}
@Override
public String getRepositoryImage()
{
return getImage(
URI.createURI("https://git.eclipse.org/c/equinox/rt.equinox.p2.git/plain/bundles/org.eclipse.equinox.p2.ui/icons/obj/metadata_repo_obj@2x.png"),
outputLocation);
}
@Override
public String getProviderImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde/eclipse32.png"), outputLocation);
}
@Override
public String getFeatureImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/feature_obj@2x.png"),
outputLocation);
}
@Override
public String getProductImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/product_xml_obj@2x.png"),
outputLocation);
}
public String getPluginImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/plugin_obj@2x.png"),
outputLocation);
}
@Override
public String getBundleImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/bundle_obj@2x.png"),
outputLocation);
}
@Override
public String getCategoryImage()
{
return getImage(
URI.createURI("https://git.eclipse.org/c/equinox/rt.equinox.p2.git/plain/bundles/org.eclipse.equinox.p2.ui/icons/obj/category_obj@2x.png"),
outputLocation);
}
@Override
public Map<String, List<String>> getBundles()
{
Map<String, List<String>> result = new TreeMap<>(CommonPlugin.INSTANCE.getComparator());
for (IInstallableUnit iu : allIUs)
{
String id = iu.getId();
List<String> lines = new ArrayList<>();
for (IProvidedCapability providedCapability : iu.getProvidedCapabilities())
{
String namespace = providedCapability.getNamespace();
String name = providedCapability.getName();
if ("org.eclipse.equinox.p2.eclipse.type".equals(namespace) && "bundle".equals(name))
{
String iuName = iu.getProperty("org.eclipse.equinox.p2.name", null);
iuName += " " + iu.getVersion();
iuName = iuName.substring(0, iuName.lastIndexOf('.'));
if (!result.containsKey(iuName))
{
lines.add(0, "\u21D6 " + id + " " + iu.getVersion());
result.put(iuName, lines);
}
}
else if ("java.package".equals(namespace))
{
Version version = providedCapability.getVersion();
lines.add("\u2196 " + name + (Version.emptyVersion.equals(version) ? "" : " " + version));
}
}
for (IRequirement requirement : iu.getRequirements())
{
if (requirement instanceof IRequiredCapability)
{
IRequiredCapability requiredCapability = (IRequiredCapability)requirement;
String namespace = requiredCapability.getNamespace();
String line = null;
if ("osgi.bundle".equals(namespace))
{
line = "\u21D8 ";
}
else if ("java.package".equals(namespace))
{
line = "\u2198 ";
}
if (line != null)
{
String name = requiredCapability.getName();
VersionRange range = requiredCapability.getRange();
line += name;
if (!VersionRange.emptyRange.equals(range))
{
line += " " + range;
}
if (requiredCapability.getMin() == 0)
{
line += " optional";
if (requiredCapability.isGreedy())
{
line += " greedy";
}
}
lines.add(line);
}
}
}
}
return result;
}
@Override
public List<IUReport> getIUReports()
{
List<IUReport> result = new ArrayList<>();
for (final IInstallableUnit iu : allIUs)
{
class MyIUReport extends IUReport
{
@Override
public Report getReport()
{
return MyReport.this;
}
@Override
public String getNow()
{
return getReport().getNow();
}
@Override
public IInstallableUnit getIU()
{
return iu;
}
@Override
public String getDescription()
{
String description = iu.getProperty(IInstallableUnit.PROP_DESCRIPTION, null);
return description;
}
@Override
public String getProvider()
{
String provider = iu.getProperty(IInstallableUnit.PROP_PROVIDER, null);
return provider;
}
@Override
public String getReportBrandingImage()
{
return "../" + getReport().getReportBrandingImage();
}
@Override
public String getHelpLink()
{
return "https://wiki.eclipse.org/Oomph_Repository_Analyzer#Installable_Unit_Pages";
}
@Override
public String getHelpImage()
{
return "../" + getReport().getHelpImage();
}
@Override
public String getHelpText()
{
return "installable unit index";
}
@Override
public String getReportSource()
{
return getReport().getReportSource();
}
@Override
public String getTitle()
{
return iu.toString();
}
@Override
public String getTitle(boolean narrow)
{
String id = iu.getId();
Version version = iu.getVersion();
return narrow ? id + "<br/><span style=\"color: DarkOliveGreen;\">" + version + "</span>" : id + " " + version;
}
@Override
public String getRelativeReportURL()
{
return getRelativeIUReportURL(iu);
}
@Override
public Map<String, String> getBreadcrumbs()
{
Map<String, String> breadcrumbs = new LinkedHashMap<>(getReport().getBreadcrumbs());
for (Map.Entry<String, String> entry : breadcrumbs.entrySet())
{
String href = entry.getValue();
entry.setValue(href == null ? "../" + getReport().getRelativeIndexURL() : "../" + href);
}
breadcrumbs.put(iu.toString(), null);
return breadcrumbs;
}
@Override
public Map<String, String> getNavigation()
{
Map<String, String> navigation = new LinkedHashMap<>();
if (!aggregator)
{
navigation.put("../" + getReport().getRelativeIndexURL(), getReport().getTitle(true));
}
return navigation;
}
}
result.add(new MyIUReport());
}
return result;
}
}
report = new MyReport();
if (metadataRepository instanceof ICompositeRepository<?>)
{
ICompositeRepository<?> compositeRepository = (ICompositeRepository<?>)metadataRepository;
List<java.net.URI> children = compositeRepository.getChildren();
for (java.net.URI child : children)
{
Report childReport = generateReport(report, rootURI, rootOutputLocation, toExternalRepositoryLocation(child), outputLocation, artifactCache,
artifactCacheFolder, reportSource, reportBranding);
childReports.add(childReport);
}
}
reports.put(uri, report);
}
return report;
}
private Set<IInstallableUnit> getAllIUs(IMetadataRepository metadataRepository)
{
if (isAggrconRepository(metadataRepository))
{
Set<IInstallableUnit> allIUs = new TreeSet<>();
Map<String, String> properties = metadataRepository.getProperties();
for (Map.Entry<String, String> entry : properties.entrySet())
{
URI uri = URI.createURI(entry.getKey());
String scheme = uri.scheme();
if ("http".equals(scheme) || "https".equals(scheme))
{
List<String> requirements = StringUtil.explode(entry.getValue(), ";");
for (String requirement : requirements)
{
List<String> parts = StringUtil.explode(requirement, " ");
String id = parts.get(0);
IQuery<IInstallableUnit> iuQuery = parts.size() > 1 ? QueryUtil.createIUQuery(id, VersionRange.create(parts.get(1))) : QueryUtil.createIUQuery(id);
Set<IInstallableUnit> result = query(metadataRepository, QueryUtil.createCompoundQuery(iuQuery, QueryUtil.createLatestIUQuery(), true));
if (result.isEmpty())
{
System.err.println("### not found " + requirement + " in" + metadataRepository.getLocation());
}
else
{
IInstallableUnit iu = result.iterator().next();
collectChildren(metadataRepository, allIUs, iu);
}
}
}
}
return allIUs;
}
Set<IInstallableUnit> allIUs = query(metadataRepository, QueryUtil.createIUAnyQuery());
return allIUs;
}
private void collectChildren(IMetadataRepository metadataRepository, Set<IInstallableUnit> allIUs, IInstallableUnit iu)
{
if (allIUs.add(iu))
{
for (IRequirement requirement : iu.getRequirements())
{
if (requirement instanceof IRequiredCapability)
{
IRequiredCapability requiredCapability = (IRequiredCapability)requirement;
if (IInstallableUnit.NAMESPACE_IU_ID.equals(requiredCapability.getNamespace()))
{
VersionRange range = requiredCapability.getRange();
Version minimum = range.getMinimum();
if (minimum.equals(range.getMaximum()))
{
Set<IInstallableUnit> result = query(metadataRepository, QueryUtil.createIUQuery(requiredCapability.getName(), minimum));
if (result.isEmpty())
{
System.err.println("### not found " + requirement + " in" + metadataRepository.getLocation());
}
else
{
IInstallableUnit requiredIU = result.iterator().next();
collectChildren(metadataRepository, allIUs, requiredIU);
}
}
}
}
}
}
}
private Future<List<String>> getIndex(final File file)
{
final String path = file.toString();
final File effectiveFile = path.endsWith(".pack.gz") ? new File(path + PROCESSED) : file;
Future<List<String>> future = fileIndices.get(effectiveFile);
if (future == null)
{
future = getExecutor().submit(new Callable<List<String>>()
{
@Override
public List<String> call() throws Exception
{
final List<String> result = new ArrayList<>();
ZIPUtil.unzip(effectiveFile, new ZIPUtil.UnzipHandler()
{
@Override
public void unzipFile(String name, InputStream zipStream) throws IOException
{
result.add(name);
}
@Override
public void unzipDirectory(String name) throws IOException
{
}
});
return result;
}
});
fileIndices.put(effectiveFile, future);
}
fileIndices.put(file, future);
return future;
}
private Future<URI> getBrandingImage(final IInstallableUnit iu, final IMetadataRepository metadataRepository, final IArtifactRepository artifactRepository,
Map<IInstallableUnit, Future<URI>> brandingImages, final Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache, final File cache)
{
Future<URI> result = brandingImages.get(iu);
if (result == null)
{
final String id = iu.getId();
final String baseID = id.replaceAll("(\\.source)?\\.feature\\.group$", "");
if (id.endsWith(".source.feature.group"))
{
IQueryResult<IInstallableUnit> query = metadataRepository.query(QueryUtil.createIUQuery(baseID + ".feature.group"), new NullProgressMonitor());
if (!query.isEmpty())
{
result = getBrandingImage(P2Util.asIterable(query).iterator().next(), metadataRepository, artifactRepository, brandingImages, artifactCache, cache);
brandingImages.put(iu, result);
return result;
}
}
String jarID = baseID + ".feature.jar";
Version version = iu.getVersion();
IQueryResult<IInstallableUnit> jarQuery = metadataRepository.query(QueryUtil.createIUQuery(jarID, version), new NullProgressMonitor());
final List<Future<Map<IArtifactDescriptor, File>>> futures = new ArrayList<>();
for (IInstallableUnit jarIU : P2Util.asIterable(jarQuery))
{
Collection<IArtifactKey> artifacts = jarIU.getArtifacts();
for (IArtifactKey artifactKey : artifacts)
{
futures.add(getArtifacts(artifactKey, artifactRepository, artifactCache, cache));
}
}
result = getExecutor().submit(new Callable<URI>()
{
@Override
public URI call() throws Exception
{
for (Future<Map<IArtifactDescriptor, File>> future : futures)
{
Collection<File> values = future.get().values();
for (File file : values)
{
URI artifactURI = URI.createFileURI(file.toString());
if ("jar".equals(artifactURI.fileExtension()))
{
URI featureXML = URI.createURI("archive:" + artifactURI + "!/feature.xml");
Document document = loadXML(featureXML);
Element documentElement = document.getDocumentElement();
String plugin = documentElement.getAttribute("plugin");
if (StringUtil.isEmpty(plugin))
{
plugin = baseID;
}
IQueryResult<IInstallableUnit> query = metadataRepository.query(QueryUtil.createIUQuery(plugin), new NullProgressMonitor());
for (IInstallableUnit brandingPlugin : P2Util.asIterable(query))
{
for (IArtifactKey artifactKey : brandingPlugin.getArtifacts())
{
Future<Map<IArtifactDescriptor, File>> artifactCacheFuture = artifactCache.get(artifactKey);
if (artifactCacheFuture != null)
{
for (File brandingFile : artifactCacheFuture.get().values())
{
URI brandingArtifactURI = URI.createFileURI(brandingFile.toString());
if ("jar".equals(brandingArtifactURI.fileExtension()))
{
URI aboutINI = URI.createURI("archive:" + brandingArtifactURI + "!/about.ini");
try
{
Properties properties = loadProperties(aboutINI);
Object featureImage = properties.get("featureImage");
if (featureImage != null)
{
URI brandingImageURI = URI.createURI("archive:" + brandingArtifactURI + "!/" + featureImage.toString().replaceAll("^/*", ""));
return brandingImageURI;
}
}
catch (IOException ex)
{
//$FALL-THROUGH$
}
}
}
}
}
}
}
return null;
}
}
return null;
}
});
brandingImages.put(iu, result);
}
return result;
}
private Properties loadProperties(URI uri) throws IOException
{
Properties properties = new Properties();
InputStream propertiesIn = null;
try
{
propertiesIn = URIConverter.INSTANCE.createInputStream(uri);
properties.load(propertiesIn);
return properties;
}
finally
{
IOUtil.close(propertiesIn);
}
}
private Document loadXML(URI uri) throws IOException, ParserConfigurationException, SAXException
{
DocumentBuilder documentBuilder = XMLUtil.createDocumentBuilder();
InputStream in = null;
try
{
in = URIConverter.INSTANCE.createInputStream(uri);
Document document = XMLUtil.loadDocument(documentBuilder, in);
return document;
}
finally
{
IOUtil.close(in);
}
}
private byte[] getImageBytes(URI imageURI)
{
byte[] bytes = imageBytes.get(imageURI);
if (bytes == null)
{
InputStream in = null;
try
{
in = URIConverter.INSTANCE.createInputStream(imageURI);
ByteArrayOutputStream out = new ByteArrayOutputStream();
IOUtil.copy(in, out);
bytes = out.toByteArray();
}
catch (IOException ex)
{
System.err.println("###" + ex.getLocalizedMessage());
bytes = getImageBytes(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/error_st_obj@2x.png"));
}
finally
{
IOUtil.close(in);
}
imageBytes.put(imageURI, bytes);
}
return bytes;
}
private String getImage(URI imageURI, File cache)
{
String result = images.get(imageURI);
if (result == null || !new File(cache, result).isFile())
{
String key = null;
OutputStream imageOut = null;
try
{
byte[] imageBytes = getImageBytes(imageURI);
key = IOUtil.encodeFileName(XMLTypeFactory.eINSTANCE.convertBase64Binary(IOUtil.getSHA1(new ByteArrayInputStream(imageBytes))).replace('=', '_'));
result = images.get(key);
if (result == null)
{
String location = key + '.' + imageURI.fileExtension();
File locationFile = new File(cache, location);
imageOut = new FileOutputStream(locationFile);
IOUtil.copy(new ByteArrayInputStream(imageBytes), imageOut);
result = location;
images.put(key, result);
images.put(imageURI, result);
}
}
catch (IOException ex)
{
result = getErrorImage(cache);
images.put(imageURI, result);
if (key != null)
{
images.put(key, result);
}
}
catch (NoSuchAlgorithmException ex)
{
//$FALL-THROUGH$
}
finally
{
IOUtil.close(imageOut);
}
}
return result;
}
private String getOKImage(File cache)
{
return getImage(URI.createURI("https://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/bundles/org.eclipse.ui/icons/full/obj16/activity@2x.png"),
cache);
}
private String getErrorImage(File cache)
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/error_st_obj@2x.png"), cache);
}
private String getWarningImage(File cache)
{
return getImage(URI.createURI("https://git.eclipse.org/c/pde/eclipse.pde.ui.git/plain/ui/org.eclipse.pde.ui/icons/obj16/warning_st_obj@2x.png"), cache);
}
private String getImage(String pluginID, String imagePath, File cache)
{
Bundle bundle = Platform.getBundle(pluginID);
URL imageLocationURL = bundle.getEntry(imagePath);
URI imagelocationURI = URI.createURI(imageLocationURL.toString());
return getImage(imagelocationURI, cache);
}
private Future<Map<IArtifactDescriptor, File>> getArtifacts(final IArtifactKey artifactKey, final IArtifactRepository artifactRepository,
Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache, final File cache)
{
Future<Map<IArtifactDescriptor, File>> result = artifactCache.get(artifactKey);
if (result == null)
{
result = getExecutor().submit(new Callable<Map<IArtifactDescriptor, File>>()
{
@Override
public Map<IArtifactDescriptor, File> call() throws Exception
{
Map<IArtifactDescriptor, File> artifacts = new LinkedHashMap<>();
IArtifactDescriptor[] artifactDescriptors = artifactRepository.getArtifactDescriptors(artifactKey);
for (IArtifactDescriptor artifactDescriptor : artifactDescriptors)
{
IArtifactRepository repository = artifactDescriptor.getRepository();
if (repository instanceof SimpleArtifactRepository)
{
SimpleArtifactRepository simpleArtifactRepository = (SimpleArtifactRepository)repository;
java.net.URI artifactLocation = simpleArtifactRepository.getLocation(artifactDescriptor);
java.net.URI location = repository.getLocation();
java.net.URI relativeLocation = location.relativize(artifactLocation);
File targetLocation = new File(cache, relativeLocation.toString());
if (!targetLocation.isFile())
{
targetLocation.getParentFile().mkdirs();
String uuid = EcoreUtil.generateUUID();
File downloadLocation = new File(targetLocation.getPath() + "." + uuid);
IStatus status = Status.CANCEL_STATUS;
for (int i = 1; i <= DOWNLOAD_RETRY_COUNT; ++i)
{
FileOutputStream out = null;
try
{
out = new FileOutputStream(downloadLocation);
status = artifactRepository.getRawArtifact(artifactDescriptor, out, new NullProgressMonitor());
if (!status.isOK())
{
throw new IOException("Failed to download: '" + downloadLocation + "' because " + status.getMessage());
}
IOUtil.closeSilent(out);
if (!downloadLocation.renameTo(targetLocation))
{
throw new IOException("Could not rename '" + downloadLocation + "' to '" + targetLocation + "'");
}
if (relativeLocation.toString().startsWith("binary/"))
{
ZIPUtil.unzip(targetLocation, new File(cache, "binary/unpacked/" + relativeLocation.toString().substring("binary/".length())));
}
}
catch (Exception ex)
{
IOUtil.close(out);
targetLocation.delete();
downloadLocation.delete();
if (i == DOWNLOAD_RETRY_COUNT)
{
new FileOutputStream(targetLocation).close();
OutputStream failure = new FileOutputStream(new File(targetLocation + ".fail"));
PrintStream printStream = new PrintStream(failure);
printStream.print(status);
printStream.close();
System.err.println("Failed: " + targetLocation);
break;
}
System.err.println("Retrying: " + targetLocation);
continue;
}
finally
{
downloadLocation.delete();
IOUtil.close(out);
}
if (validZip(targetLocation))
{
break;
}
}
IProcessingStepDescriptor[] processingSteps = artifactDescriptor.getProcessingSteps();
if (processingSteps.length != 0 || artifactDescriptor.getProperty(PGPSignatureVerifier.PGP_SIGNATURES_PROPERTY_NAME) != null)
{
File targetProcessedLocation = new File(cache, relativeLocation.toString() + PROCESSED);
File processedDownloadLocation = new File(targetProcessedLocation.getPath() + "." + uuid);
for (int i = 1; i <= DOWNLOAD_RETRY_COUNT; ++i)
{
FileOutputStream out = null;
status = Status.CANCEL_STATUS;
try
{
ArtifactDescriptor descriptor = new ArtifactDescriptor(artifactKey);
class DescriptorOutputStream extends FileOutputStream implements IAdaptable
{
public DescriptorOutputStream(File file) throws FileNotFoundException
{
super(file);
}
@Override
public <T> T getAdapter(Class<T> adapter)
{
if (adapter.isInstance(descriptor))
{
return adapter.cast(descriptor);
}
return null;
}
}
out = new DescriptorOutputStream(processedDownloadLocation);
status = artifactRepository.getArtifact(artifactDescriptor, out, new NullProgressMonitor());
if (!status.isOK())
{
throw new IOException("Failed to download: '" + processedDownloadLocation + "' because " + status.getMessage());
}
IOUtil.closeSilent(out);
if (!processedDownloadLocation.renameTo(targetProcessedLocation))
{
throw new IOException("Could not rename '" + processedDownloadLocation + "' to '" + targetProcessedLocation + "'");
}
String pgpKeys = descriptor.getProperty(PGPSignatureVerifier.PGP_SIGNER_KEYS_PROPERTY_NAME);
if (pgpKeys != null && !pgpKeys.isBlank())
{
IOUtil.writeUTF8(new File(targetLocation + ".asc"), pgpKeys);
}
}
catch (Exception ex)
{
IOUtil.close(out);
targetProcessedLocation.delete();
processedDownloadLocation.delete();
if (i == DOWNLOAD_RETRY_COUNT)
{
new FileOutputStream(targetProcessedLocation).close();
OutputStream failure = new FileOutputStream(new File(targetProcessedLocation + ".fail"));
PrintStream printStream = new PrintStream(failure);
printStream.print(status);
printStream.close();
System.err.println("Failed: " + targetProcessedLocation);
break;
}
System.err.println("Retrying: " + targetProcessedLocation);
continue;
}
finally
{
IOUtil.close(out);
}
if (validZip(targetProcessedLocation))
{
break;
}
}
}
}
artifacts.put(artifactDescriptor, targetLocation);
}
else
{
throw new RuntimeException("Invalid repository type " + repository);
}
}
return artifacts;
}
});
artifactCache.put(artifactKey, result);
}
return result;
}
private boolean validZip(File file)
{
if (file.length() == 0)
{
return false;
}
if (file.getName().endsWith(".pack.gz"))
{
return true;
}
try
{
File copy = new File(file.getAbsolutePath() + ".copy");
IOUtil.copyFile(file, copy);
ZIPUtil.unzip(copy, new ZIPUtil.UnzipHandler()
{
@Override
public void unzipFile(String name, InputStream zipStream) throws IOException
{
}
@Override
public void unzipDirectory(String name) throws IOException
{
}
});
return true;
}
catch (IORuntimeException ex)
{
return false;
}
}
private Map<File, Future<SignedContent>> getSignedContent(IInstallableUnit iu, final Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache,
Map<IInstallableUnit, Map<File, Future<SignedContent>>> signedContentCache)
{
Map<File, Future<SignedContent>> artifactSignedContent = signedContentCache.get(iu);
if (artifactSignedContent == null)
{
Map<IInstallableUnit, Map<File, Future<SignedContent>>> result = new LinkedHashMap<>();
final BundleContext context = P2CorePlugin.INSTANCE.getBundleContext();
ServiceReference<SignedContentFactory> contentFactoryRef = context.getServiceReference(SignedContentFactory.class);
final SignedContentFactory verifierFactory = context.getService(contentFactoryRef);
try
{
ExecutorService executor = getExecutor();
artifactSignedContent = new LinkedHashMap<>();
for (IArtifactKey artifactKey : iu.getArtifacts())
{
Future<Map<IArtifactDescriptor, File>> artifactCacheFuture = artifactCache.get(artifactKey);
if (artifactCacheFuture != null)
{
for (final File file : get(artifactCacheFuture).values())
{
Future<SignedContent> signedContent = executor.submit(new Callable<SignedContent>()
{
@Override
public SignedContent call() throws Exception
{
File processedFile = new File(file.toString() + PROCESSED);
File targetFile = processedFile.isFile() && processedFile.length() != 0 ? processedFile : file;
if (targetFile.toString().endsWith(".pack.gz") || targetFile.length() == 0)
{
return null;
}
return verifierFactory.getSignedContent(targetFile);
}
});
artifactSignedContent.put(file, signedContent);
getIndex(file);
}
}
result.put(iu, artifactSignedContent);
}
signedContentCache.put(iu, artifactSignedContent);
}
finally
{
context.ungetService(contentFactoryRef);
}
}
return artifactSignedContent;
}
private Map<File, Set<PGPPublicKey>> getPGPSignedContent(IInstallableUnit iu, final Map<IArtifactKey, Future<Map<IArtifactDescriptor, File>>> artifactCache,
Map<IInstallableUnit, Map<File, Set<PGPPublicKey>>> pgpSignedContentCache)
{
Map<File, Set<PGPPublicKey>> artifactPGPSignedContent = pgpSignedContentCache.get(iu);
if (artifactPGPSignedContent == null)
{
artifactPGPSignedContent = new LinkedHashMap<>();
for (IArtifactKey artifactKey : iu.getArtifacts())
{
Future<Map<IArtifactDescriptor, File>> artifactCacheFuture = artifactCache.get(artifactKey);
if (artifactCacheFuture != null)
{
for (Map.Entry<IArtifactDescriptor, File> entry : get(artifactCacheFuture).entrySet())
{
PGPPublicKeyStore keys = PGPSignatureVerifier.getKeys(entry.getKey());
Collection<PGPPublicKey> all = keys.all();
if (!all.isEmpty())
{
artifactPGPSignedContent.put(entry.getValue(), new LinkedHashSet<>(all));
}
}
}
}
pgpSignedContentCache.put(iu, artifactPGPSignedContent);
}
return artifactPGPSignedContent;
}
private static <T> T get(Future<T> future)
{
try
{
return future.get();
}
catch (InterruptedException ex)
{
throw new RuntimeException(ex);
}
catch (ExecutionException ex)
{
throw new RuntimeException(ex);
}
}
private static boolean isAggrconRepositoryURI(URI uri)
{
return "file".equals(uri.scheme()) && "aggrcon".equals(uri.fileExtension());
}
private static boolean isAggrconRepository(IRepository<?> repository)
{
java.net.URI location = repository.getLocation();
return "file".equals(location.getScheme()) && location.toString().endsWith(".aggrcon") && repository instanceof ICompositeRepository<?>;
}
private void loadAggrconChildren(IRepository<?> repository) throws URISyntaxException
{
if (isAggrconRepository(repository))
{
ICompositeRepository<?> aggrconRepository = (ICompositeRepository<?>)repository;
Map<String, String> properties = aggrconRepository.getProperties();
for (Map.Entry<String, String> entry : properties.entrySet())
{
String key = entry.getKey();
if (key.startsWith("http:") || key.startsWith("https:"))
{
java.net.URI child = new java.net.URI(key);
aggrconRepository.addChild(child);
}
}
}
}
private IMetadataRepository loadMetadataRepository(IMetadataRepositoryManager manager, URI uri) throws URISyntaxException, ProvisionException
{
if (verbose)
{
System.out.println("Loading metadata repository '" + uri + "'");
}
java.net.URI location = new java.net.URI(uri.toString());
IMetadataRepository metadataRepository = metadataRepositories.get(location);
if (metadataRepository == null)
{
metadataRepository = manager.loadRepository(location, null);
loadAggrconChildren(metadataRepository);
metadataRepositories.put(location, metadataRepository);
}
return metadataRepository;
}
private IArtifactRepository loadArtifactRepository(IArtifactRepositoryManager manager, URI uri) throws URISyntaxException, ProvisionException
{
if (verbose)
{
System.out.println("Loading artifact repository '" + uri + "'");
}
java.net.URI location = new java.net.URI(uri.toString());
IArtifactRepository artifactRepository = artifactRepositories.get(location);
if (artifactRepository == null)
{
artifactRepository = manager.loadRepository(location, null);
loadAggrconChildren(artifactRepository);
artifactRepositories.put(location, artifactRepository);
if (artifactRepository instanceof ICompositeRepository<?>)
{
ICompositeRepository<?> compositeRepository = (ICompositeRepository<?>)artifactRepository;
for (java.net.URI child : compositeRepository.getChildren())
{
loadArtifactRepository(manager, URI.createURI(child.toString()));
}
}
}
return artifactRepository;
}
private ExecutorService getExecutor()
{
if (executor == null)
{
executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4);
}
return executor;
}
private void shutDownExecutor() throws InterruptedException
{
if (executor != null)
{
executor.shutdown();
executor.awaitTermination(10, TimeUnit.MINUTES);
executor = null;
}
}
public Agent getAgent()
{
if (agent == null)
{
try
{
File agentLocation = File.createTempFile("test-", "-agent");
agentLocation.delete();
agentLocation.mkdirs();
agentLocation.deleteOnExit();
agent = new AgentImpl(null, agentLocation);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
return agent;
}
public void setAgent(Agent agent)
{
this.agent = agent;
}
private IMetadataRepositoryManager getMetadataRepositoryManager()
{
return getAgent().getMetadataRepositoryManager();
}
private IArtifactRepositoryManager getArtifactRepositoryManager()
{
return getAgent().getArtifactRepositoryManager();
}
private static String format(float size)
{
NumberFormat instance = NumberFormat.getInstance(Locale.US);
instance.setMaximumFractionDigits(1);
instance.setRoundingMode(RoundingMode.DOWN);
if (size < 1024f)
{
return instance.format(size);
}
else if (size < 1024f * 1024f)
{
return instance.format(size / 1024) + "K";
}
else if (size < 1024f * 1024f * 1024f)
{
return instance.format(size / 1024f / 1024f) + "M";
}
else if (size < 1024f * 1024f * 1024f * 1024f)
{
return instance.format(size / 1024f / 1024f / 1024f) + "G";
}
else
{
return instance.format(size / 1024f / 1024f / 1024f / 1024f) + "T";
}
}
private static String getIUID(IInstallableUnit iu)
{
return getID(iu.toString());
}
private static String getRequirementID(IRequirement requirement)
{
return getID(requirement.toString());
}
private static String getProvidedCapabilityID(IProvidedCapability capability)
{
return getID(capability.toString());
}
private static String getID(String literal)
{
return literal.replace(' ', '_').replace('"', '_').replace('&', '_').replace('<', '_').replace('\'', '_').replace('>', ' ').replace('#', '_').replace('/',
'_');
}
public interface Reporter
{
String getTitle();
Map<String, String> getBreadcrumbs();
Map<String, String> getNavigation();
String getTitle(boolean narrow);
String getReportBrandingImage();
String getHelpLink();
String getHelpImage();
String getHelpText();
String getReportSource();
String getNow();
}
public static abstract class Report implements Reporter
{
private static final URI NO_LICENSE_URI = URI.createURI("");
public static class LicenseDetail
{
private final URI licenseURL;
private final ILicense license;
private final ILicense matchedLicense;
private final String body;
private int prefix;
private int suffix;
private String replacement;
private LicenseDetail(URI licenseURL, ILicense license)
{
this.licenseURL = licenseURL;
this.license = license;
body = license.getBody().trim();
if (SUA_10.equals(license))
{
matchedLicense = SUA_10;
prefix = suffix = body.length();
}
else if (SUA_11.equals(license))
{
matchedLicense = SUA_11;
prefix = suffix = body.length();
}
else if (SUA_20.equals(license))
{
matchedLicense = SUA_20;
prefix = suffix = body.length();
}
else
{
ILicense bestMatch = null;
String bestMatchBody = null;
int longest = -1;
int longestMatchBody = -1;
for (ILicense otherLicense : new ILicense[] { SUA_10, SUA_11, SUA_20 })
{
String otherBody = otherLicense.getBody().trim();
boolean newLine = false;
for (int bodyIndex = 0, otherBodyIndex = 0, bodyLength = body.length(), otherBodyLength = otherBody.length(); bodyIndex < bodyLength
&& otherBodyIndex < otherBodyLength; ++bodyIndex, ++otherBodyIndex)
{
char bodyChar = body.charAt(bodyIndex);
char otherBodyChar = otherBody.charAt(otherBodyIndex);
if (Character.isWhitespace(bodyChar) && Character.isWhitespace(otherBodyChar))
{
if (bodyChar == '\n')
{
newLine = true;
}
while (++bodyIndex < bodyLength)
{
bodyChar = body.charAt(bodyIndex);
if (Character.isWhitespace(bodyChar))
{
if (bodyChar == '\n')
{
newLine = true;
}
}
else
{
break;
}
}
while (++otherBodyIndex < otherBodyLength)
{
otherBodyChar = otherBody.charAt(otherBodyIndex);
if (!Character.isWhitespace(otherBodyChar))
{
break;
}
}
}
if (bodyChar != otherBodyChar)
{
break;
}
if (bodyIndex > longest && newLine)
{
bestMatch = otherLicense;
bestMatchBody = otherBody;
longest = bodyIndex;
longestMatchBody = otherBodyIndex;
}
}
}
if (bestMatch != null)
{
prefix = longest + 1;
suffix = body.length();
for (int bodyIndex = suffix - 1, otherBodyIndex = bestMatchBody.length() - 1; bodyIndex >= 0 && otherBodyIndex >= 0; --bodyIndex, --otherBodyIndex)
{
char bodyChar = body.charAt(bodyIndex);
char otherBodyChar = bestMatchBody.charAt(otherBodyIndex);
if (Character.isWhitespace(bodyChar) && Character.isWhitespace(otherBodyChar))
{
while (--bodyIndex >= 0)
{
bodyChar = body.charAt(bodyIndex);
if (!Character.isWhitespace(bodyChar))
{
break;
}
}
while (--otherBodyIndex >= 0)
{
otherBodyChar = bestMatchBody.charAt(otherBodyIndex);
if (!Character.isWhitespace(otherBodyChar))
{
break;
}
}
}
if (bodyChar != otherBodyChar)
{
suffix = bodyIndex + 1;
replacement = bestMatchBody.substring(longestMatchBody + 1, otherBodyIndex + 1);
break;
}
}
}
else
{
prefix = 0;
suffix = body.length();
}
if (SUA_10.equals(bestMatch))
{
matchedLicense = SUA_10;
}
else if (SUA_11.equals(bestMatch))
{
matchedLicense = SUA_11;
}
else if (SUA_20.equals(bestMatch))
{
matchedLicense = SUA_20;
}
else
{
matchedLicense = null;
}
}
}
public URI getLicenseURL()
{
return licenseURL;
}
public ILicense getLicense()
{
return license;
}
public String getUUID()
{
return license.getUUID();
}
public ILicense getMatchedLicense()
{
return matchedLicense;
}
public String getMatchingPrefix()
{
return body.substring(0, prefix);
}
public String getMismatching()
{
return body.substring(prefix, suffix);
}
public String getReplacement()
{
return replacement == null ? "" : replacement;
}
public String getMatchingSuffix()
{
return body.substring(suffix);
}
public boolean isSUA()
{
return SUAS.contains(license);
}
public boolean isMatchedSUA()
{
return SUAS.contains(matchedLicense);
}
public String getVersion()
{
int index = SUAS.indexOf(license);
if (index == -1)
{
index = SUAS.indexOf(matchedLicense);
}
switch (index)
{
case 0:
{
return "SUA 1.0";
}
case 1:
{
return "SUA 1.1";
}
case 2:
{
return "SUA 2.0";
}
}
return getSummary();
}
public String getSummary()
{
return license.getBody().replaceAll("[\n\r].*", "");
}
}
public static final ILicense NO_LICENSE;
static
{
try
{
NO_LICENSE = MetadataFactory.createLicense(new java.net.URI("https://wwww.eclipse.org"), "No License");
}
catch (URISyntaxException ex)
{
throw new RuntimeException(ex);
}
}
public static final ILicense SUA_10 = load(URI.createURI("https://www.eclipse.org/legal/epl-v10.html"),
URI.createURI("https://raw.githubusercontent.com/eclipse-cbi/epl-license-feature/license-1.0.0.v20131003-1638/org.eclipse.license/feature.properties"));
public static final ILicense SUA_11 = load(URI.createURI("https://www.eclipse.org/legal/epl-v10.html"),
URI.createURI("https://raw.githubusercontent.com/eclipse-cbi/epl-license-feature/license-1.0.1.v20140414-1359/org.eclipse.license/feature.properties"));
public static final ILicense SUA_20 = load(URI.createURI("https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html"),
URI.createURI("https://raw.githubusercontent.com/eclipse-cbi/epl-license-feature/license-2.0.1.v20180423-1114/org.eclipse.license/feature.properties"));
public static final List<ILicense> SUAS = Collections.unmodifiableList(Arrays.asList(new ILicense[] { SUA_10, SUA_11, SUA_20 }));
public static final int RETAINED_NIGHTLY_BUILDS = -1;
@Override
public abstract String getReportSource();
@Override
public abstract String getReportBrandingImage();
public abstract Map<Report.LicenseDetail, Set<IInstallableUnit>> getLicenses();
public abstract List<String> getFeatures(Iterable<IInstallableUnit> features);
@Override
public abstract Map<String, String> getBreadcrumbs();
public List<String> getXML(IInstallableUnit iu)
{
return getXML(iu, null);
}
public abstract List<String> getXML(IInstallableUnit iu, Map<String, String> replacements);
public abstract String getErrorImage();
public abstract Report getParent();
public abstract List<Report> getChildren();
public abstract String getBrandingImage(IInstallableUnit iu);
public abstract boolean hasBrandingImage(IInstallableUnit iu);
public abstract boolean hasBrokenBrandingImage(IInstallableUnit iu);
public abstract Map<String, Set<IInstallableUnit>> getFeatureProviders();
public abstract Set<String> getBrandingImages(Collection<IInstallableUnit> ius);
public abstract String getSignedImage(boolean signed);
public abstract String getLicenseImage();
public abstract String getRepositoryImage();
public abstract String getProviderImage();
public abstract String getFeatureImage();
public abstract String getProductImage();
public abstract String getCategoryImage();
public abstract String getBundleImage();
public abstract Map<String, String> getCertificateComponents(Certificate certificate);
public abstract boolean isExpired(Certificate certificate);
public abstract Map<List<Certificate>, Map<String, IInstallableUnit>> getCertificates();
public abstract String getKeyServerURL(PGPPublicKey key);
public abstract Map<PGPPublicKey, Map<String, IInstallableUnit>> getPGPKeys();
public abstract Set<List<Certificate>> getCertificates(IInstallableUnit iu);
public abstract Set<PGPPublicKey> getPGPKeys(IInstallableUnit iu);
public abstract Map<String, Boolean> getIUArtifacts(IInstallableUnit iu);
public abstract String getRepositoryURL(String artifact);
public abstract List<String> getArtifactStatus(String artifact);
public abstract String getArtifactImage(String artifact);
public abstract String getArtifactSize(String artifact);
public abstract Map<String, Set<Version>> getIUVersions();
public abstract Set<IInstallableUnit> getUnsignedIUs();
public abstract Set<IInstallableUnit> getBadProviderIUs();
public abstract Set<IInstallableUnit> getBadLicenseIUs();
public abstract Set<IInstallableUnit> getBrokenBrandingIUs();
public abstract Set<IInstallableUnit> getClassContainingIUs();
public abstract boolean isSimple();
public abstract boolean isRoot();
public abstract String getDate();
@Override
public String getNow()
{
return new SimpleDateFormat("yyyy'-'MM'-'dd' at 'HH':'mm ").format(System.currentTimeMillis());
}
public abstract List<String> getFeatures();
public abstract List<IInstallableUnit> getFeatureIUs();
public boolean isFeature(IInstallableUnit iu)
{
String id = iu.getId();
return id.endsWith(Requirement.FEATURE_SUFFIX);
}
public abstract List<Report.LicenseDetail> getLicenses(IInstallableUnit iu);
public String getName(IInstallableUnit iu, boolean defaultToID)
{
String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
if (name == null)
{
name = iu.getId();
}
return name;
}
public String getVersion(IInstallableUnit iu)
{
return iu.getVersion().toString();
}
public String getNameAndVersion(IInstallableUnit iu)
{
String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
name += " " + iu.getVersion();
return name;
}
public abstract Map<String, List<String>> getBundles();
public abstract boolean isDuplicationExpected(String id);
public abstract Set<IInstallableUnit> getAllIUs();
public Set<IInstallableUnit> getSortedByName(Collection<? extends IInstallableUnit> ius)
{
TreeSet<IInstallableUnit> result = new TreeSet<>(NAME_VERSION_COMPARATOR);
result.addAll(ius);
return result;
}
public abstract Set<IInstallableUnit> getProducts();
public Set<IInstallableUnit> getCategories()
{
Set<IInstallableUnit> categories = new TreeSet<>();
for (IInstallableUnit iu : getAllIUs())
{
if (isCategory(iu))
{
categories.add(iu);
}
}
return categories;
}
public boolean isCategory(IInstallableUnit iu)
{
return "true".equals(iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_CATEGORY));
}
public boolean isGroup(IInstallableUnit iu)
{
return "true".equals(iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_GROUP));
}
public boolean isProduct(IInstallableUnit iu)
{
return "true".equals(iu.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_PRODUCT));
}
public boolean isPlugin(IInstallableUnit iu)
{
return !isCategory(iu) && !isGroup(iu);
}
public abstract String getIUImage(IInstallableUnit iu);
public abstract Set<IInstallableUnit> getResolvedRequirements(IInstallableUnit iu);
public String getRelativeIndexURL()
{
String location = isRoot() ? "index.html" : IOUtil.encodeFileName(getSiteURL()) + ".html";
return location;
}
protected String getRelativeIUReportURL(IInstallableUnit iu)
{
URI indexURL = URI.createURI(getRelativeIndexURL());
return indexURL.trimFileExtension().appendSegment(getIUID(iu)).appendFileExtension("html").toString();
}
public String getIUID(IInstallableUnit iu)
{
return RepositoryIntegrityAnalyzer.getIUID(iu);
}
public String getFolderID(String folder)
{
return "_" + new File(folder).getName().replace('.', '_').replace('\'', '_');
}
@Override
public abstract Map<String, String> getNavigation();
public abstract String getSiteURL();
public abstract String getMetadataXML();
public abstract String getArtifactML();
@Override
public abstract String getTitle(boolean narrow);
@Override
public abstract String getTitle();
private static ILicense load(URI licenseURI, URI uri)
{
InputStream in = null;
try
{
in = URIConverter.INSTANCE.createInputStream(uri);
Properties properties = new Properties();
Reader reader = new InputStreamReader(in, "UTF-8");
properties.load(reader);
Object license = properties.get("license");
return MetadataFactory.createLicense(new java.net.URI(licenseURI.toString()), license.toString());
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
catch (URISyntaxException ex)
{
throw new IORuntimeException(ex);
}
finally
{
IOUtil.closeSilent(in);
}
}
public abstract List<IUReport> getIUReports();
}
public static abstract class IUReport implements Reporter
{
public abstract Report getReport();
public abstract String getRelativeReportURL();
public abstract IInstallableUnit getIU();
public abstract String getDescription();
public abstract String getProvider();
}
public class IndexReport implements Reporter
{
private final IndexReport parent;
private final String reportSource;
private final String reportBranding;
private final File folder;
private final Set<File> reportLocations;
private final Map<String, String> allReports;
private final File publishLocation;
private final Set<File> reportsWithErrors;
private List<IndexReport> children;
public IndexReport(IndexReport parent, String reportSource, String reportBranding, File folder, File publishLocation, Set<File> reportLocations,
Map<String, String> allReports, Set<File> reportsWithErrors)
{
this.parent = parent;
this.reportSource = reportSource;
this.reportBranding = reportBranding;
this.folder = folder;
this.publishLocation = publishLocation;
this.reportLocations = reportLocations;
this.allReports = allReports;
this.reportsWithErrors = reportsWithErrors;
}
@Override
public String getHelpLink()
{
return parent == null && aggregator ? "https://wiki.eclipse.org/Oomph_Repository_Analyzer#Simultaneous_Release"
: "https://wiki.eclipse.org/Oomph_Repository_Analyzer#Description";
}
@Override
public String getHelpImage()
{
return getImage(URI.createURI("https://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/bundles/org.eclipse.jface/icons/full/help@2x.png"),
folder);
}
@Override
public String getHelpText()
{
return parent == null && aggregator ? "simrel aggregator" : "folder index";
}
@Override
public String getNow()
{
return new SimpleDateFormat("yyyy'-'MM'-'dd' at 'HH':'mm ").format(System.currentTimeMillis());
}
public File getFolder()
{
return folder;
}
public File getPublishLocation()
{
return publishLocation;
}
@Override
public String getTitle()
{
return folder.getName();
}
@Override
public Map<String, String> getBreadcrumbs()
{
Map<String, String> result = parent == null ? new LinkedHashMap<>() : parent.getBreadcrumbs();
for (Map.Entry<String, String> entry : result.entrySet())
{
String href = entry.getValue();
entry.setValue(href == null ? "../index.html" : "../" + href);
}
result.put(folder.getName(), null);
return result;
}
@Override
public Map<String, String> getNavigation()
{
Map<String, String> result = new LinkedHashMap<>();
for (File file : listSortedFiles(folder))
{
if (file.isDirectory() && (!reportLocations.contains(file) || parent != null || aggregator && file.getName().endsWith(".aggrcon")))
{
String name = file.getName();
String label = name;
if (reportsWithErrors.contains(file))
{
String errorImage = getErrorImage(getFolder());
label = "<img style=\"position: static;\" class=\"fit-image\" src=\"" + errorImage + "\"/> " + label.replaceAll("\\.aggrcon$", "");
}
else if (name.endsWith(".aggrcon"))
{
String okImage = getOKImage(getFolder());
label = "<img style=\"position: static;\" class=\"fit-image\" src=\"" + okImage + "\"/> " + label.replaceAll("\\.aggrcon$", "");
}
result.put(name + "/index.html", label);
}
}
return result;
}
@Override
public String getTitle(boolean narrow)
{
return getTitle();
}
@Override
public String getReportSource()
{
return reportSource;
}
@Override
public String getReportBrandingImage()
{
return getImage(URI.createURI(reportBranding), folder);
}
public List<IndexReport> getChildren()
{
if (children == null)
{
children = new ArrayList<>();
for (File file : listSortedFiles(folder))
{
if (file.isDirectory() && !reportLocations.contains(file))
{
File childPulishLocation = publishLocation == null ? null : new File(publishLocation, file.getName());
children.add(new IndexReport(this, reportSource, reportBranding, file, childPulishLocation, reportLocations, null, reportsWithErrors));
}
}
}
return children;
}
public Map<String, String> getAllReports()
{
if (allReports != null)
{
Map<String, String> result = new TreeMap<>();
java.net.URI baseURI = folder.toURI();
for (Map.Entry<String, String> entry : allReports.entrySet())
{
String site = entry.getKey();
if (!site.startsWith("file:"))
{
result.put(site, baseURI.relativize(new File(entry.getValue()).toURI()).toString());
}
}
return result;
}
return null;
}
}
public static class InstallableUnitWriter extends MetadataWriter
{
private ByteArrayOutputStream output;
public InstallableUnitWriter()
{
this(new ByteArrayOutputStream());
}
private InstallableUnitWriter(OutputStream output)
{
super(output, null);
this.output = (ByteArrayOutputStream)output;
}
public String toHTML(IInstallableUnit iu, ValueHandler valueHandler)
{
try
{
super.writeInstallableUnit(iu);
flush();
byte[] bytes = output.toByteArray();
output.reset();
Resource resource = new HTMLResource(valueHandler);
resource.load(new ByteArrayInputStream(bytes), null);
StringWriter writer = new StringWriter();
resource.save(new URIConverter.WriteableOutputStream(writer, "UTF-8"), null);
return writer.toString();
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
finally
{
flush();
output.reset();
}
}
public String expandEntities(String xmlElementContent)
{
Resource resource = new HTMLResource(null);
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<element>" + xmlElementContent + "</element>";
ReadableInputStream input = new URIConverter.ReadableInputStream(xml);
try
{
resource.load(input, null);
EObject documentRoot = resource.getContents().get(0);
AnyType anyType = (AnyType)documentRoot.eContents().get(0);
Object value = anyType.getMixed().get(0).getValue();
return value.toString();
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static class ValueHandler
{
protected String getCurrentElementName(List<String> elementNames)
{
int size = elementNames.size();
return size == 0 ? "" : elementNames.get(size - 1);
}
public String handleAttributeValue(List<String> elementNames, String attributeName, String attributeValue)
{
return attributeValue;
}
public String handleElementContent(List<String> elementNames, String elementContent)
{
return elementContent;
}
public void startElement(List<String> elementNames, String uuid)
{
}
}
private static class HTMLResource extends XMLResourceImpl
{
private static final URI RESOURCE_URI = URI.createURI("iu.xml");
private static final XMLParserPool XML_PARSER_POOL = new XMLParserPoolImpl();
private final ValueHandler valueHandler;
public HTMLResource(ValueHandler valueHandler)
{
super(RESOURCE_URI);
this.valueHandler = valueHandler;
setEncoding("UTF-8");
Map<Object, Object> defaultLoadOptions = getDefaultLoadOptions();
BasicExtendedMetaData extendedMetaData = new BasicExtendedMetaData();
defaultLoadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
getDefaultSaveOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
defaultLoadOptions.put(XMLResource.OPTION_USE_LEXICAL_HANDLER, Boolean.TRUE);
defaultLoadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE);
defaultLoadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE);
defaultLoadOptions.put(XMLResource.OPTION_USE_PARSER_POOL, XML_PARSER_POOL);
XMLOptions xmlOptions = new XMLOptionsImpl();
xmlOptions.setProcessAnyXML(true);
defaultLoadOptions.put(XMLResource.OPTION_XML_OPTIONS, xmlOptions);
}
@Override
protected XMLSave createXMLSave()
{
return new HTMLSave(createXMLHelper(), valueHandler);
}
private static class HTMLSave extends XMLSaveImpl
{
private final ValueHandler valueHandler;
public HTMLSave(XMLHelper helper, ValueHandler valueHandler)
{
super(helper);
this.valueHandler = valueHandler;
}
@Override
protected void init(XMLResource resource, Map<?, ?> options)
{
super.init(resource, options);
doc = new HTMLString(valueHandler);
declareXML = false;
}
private static class HTMLString extends XMLString
{
private static final String LINE_SEPARATOR = "\n";
private static final String LINE_ELEMENT_NAME = "span";
private static final String LINE_ELEMENT_START_PREFIX = "<" + LINE_ELEMENT_NAME;
private static final String LINE_ELEMENT_END = "</" + LINE_ELEMENT_NAME + ">";
private static final String LINE_ELEMENT_SEPARATOR_PREFIX = LINE_ELEMENT_END + LINE_SEPARATOR + LINE_ELEMENT_START_PREFIX;
private static final String ATTRIBUTE_QUOTE = "<span class='xml-token'>\"</span>";
private static final String ATTRIBUTE_EQUALS = "<span class='xml-token'>=</span>";
private static final String ELEMENT_START = "<span class='xml-token'>&lt;</span>";
private static final String ELEMENT_END = "<span class='xml-token'>&gt;</span>";
private static final String EMPTY_ELEMENT_END = "<span class='xml-token'>/&gt;</span>";
private static final String ELEMENT_CLOSE_START = "<span class='xml-token'>&lt;/</span>";
private static final String ATTRIBUTE_NAME_START = "<span class='xml-attribute'>";
private static final String ATTRIBUTE_NAME_END = "</span>";
private static final String ELEMENT_NAME_START = "<span class='xml-element'>";
private static final String ELEMENT_NAME_END = "</span>";
private static final String ATTRIBUTE_VALUE_START = "<span class='xml-attribute-value'>";
private static final String ATTRIBUTE_VALUE_END = "</span>";
private static final Pattern ELEMENT_VALUE_PATTERN = Pattern.compile("((\\S+[\\s&&[^\n\r]]*)+)");
private static final String ELEMENT_VALUE_REPLACEMENT = "<span class='xml-element-value'>$1</span>";
private static final String ATTRIBUTE_SEPARATOR = " ";
private static final long serialVersionUID = 1L;
private final ValueHandler valueHandler;
private String uuid;
public HTMLString(ValueHandler valueHandler)
{
super(Integer.MAX_VALUE);
this.valueHandler = valueHandler;
setLineSeparator(LINE_SEPARATOR);
add(LINE_ELEMENT_START_PREFIX);
addLineID();
}
private void addLineID()
{
add(" id=\"");
uuid = EcoreUtil.generateUUID();
add(uuid);
add("\">");
}
private String replaceLineSeparator(String string)
{
Matcher matcher = Pattern.compile("\r?\n").matcher(string);
StringBuffer result = new StringBuffer();
if (matcher.find())
{
do
{
matcher.appendReplacement(result, LINE_ELEMENT_SEPARATOR_PREFIX);
result.append(" id=\"");
uuid = EcoreUtil.generateUUID();
result.append(uuid);
result.append("\">");
} while (matcher.find());
matcher.appendTail(result);
return result.toString();
}
return string;
}
private String surroundElementContent(String string)
{
return ELEMENT_VALUE_PATTERN.matcher(string).replaceAll(ELEMENT_VALUE_REPLACEMENT);
}
@Override
public void add(String string)
{
super.add(replaceLineSeparator(string));
}
@Override
public void addText(String string)
{
String elementContent = valueHandler.handleElementContent(elementNames, string);
if (string.equals(elementContent))
{
super.addText(replaceLineSeparator(surroundElementContent(string)));
}
else
{
super.addText(elementContent);
}
}
@Override
public void addAttribute(String name, String value)
{
add(ATTRIBUTE_SEPARATOR);
add(ATTRIBUTE_NAME_START);
add(name);
add(ATTRIBUTE_NAME_END);
add(ATTRIBUTE_EQUALS);
add(ATTRIBUTE_QUOTE);
String attributeValue = valueHandler.handleAttributeValue(elementNames, name, value);
if (attributeValue.equals(value))
{
add(ATTRIBUTE_VALUE_START);
add(value);
add(ATTRIBUTE_VALUE_END);
}
else
{
add(attributeValue);
}
add(ATTRIBUTE_QUOTE);
}
@Override
protected void closeStartElement()
{
add(ELEMENT_END);
lastElementIsStart = false;
}
@Override
public void startElement(String name)
{
if (lastElementIsStart)
{
closeStartElement();
}
elementNames.add(name);
if (name != null)
{
++depth;
add(ELEMENT_START);
add(ELEMENT_NAME_START);
add(name);
valueHandler.startElement(elementNames, uuid);
add(ELEMENT_NAME_END);
lastElementIsStart = true;
}
mixed.add(Boolean.TRUE);
}
@Override
public void endElement()
{
if (lastElementIsStart)
{
endEmptyElement();
}
else
{
String name = removeLast();
if (name != null)
{
add(ELEMENT_CLOSE_START);
add(ELEMENT_NAME_START);
add(name);
add(ELEMENT_NAME_END);
add(ELEMENT_END);
}
}
if (elementNames.isEmpty())
{
add(LINE_ELEMENT_END);
}
}
@Override
public void endContentElement(String content)
{
add(ELEMENT_END);
super.addText(replaceLineSeparator(surroundElementContent(content)));
add(ELEMENT_CLOSE_START);
String name = removeLast();
add(ELEMENT_NAME_START);
add(name);
add(ELEMENT_NAME_END);
add(ELEMENT_END);
lastElementIsStart = false;
}
@Override
public void endEmptyElement()
{
removeLast();
add(EMPTY_ELEMENT_END);
lastElementIsStart = false;
}
}
}
}
}
}