/******************************************************************************* * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. ******************************************************************************/ package org.eclipse.buckminster.rmap.psf.extension; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import java.util.Map; import java.util.UUID; import java.util.regex.Pattern; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.XMLConstants; import org.eclipse.buckminster.core.common.model.Documentation; import org.eclipse.buckminster.core.common.model.Format; import org.eclipse.buckminster.core.cspec.model.ComponentRequest; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.query.builder.AdvisorNodeBuilder; import org.eclipse.buckminster.core.query.builder.ComponentQueryBuilder; import org.eclipse.buckminster.core.query.model.ComponentQuery; import org.eclipse.buckminster.core.reader.AbstractReaderType; import org.eclipse.buckminster.core.reader.ICatalogReader; import org.eclipse.buckminster.core.reader.IComponentReader; import org.eclipse.buckminster.core.reader.IFileReader; import org.eclipse.buckminster.core.reader.IReaderType; import org.eclipse.buckminster.core.reader.IStreamConsumer; import org.eclipse.buckminster.core.reader.ReferenceInfo; import org.eclipse.buckminster.core.resolver.NodeQuery; import org.eclipse.buckminster.core.resolver.ResolutionContext; import org.eclipse.buckminster.core.resolver.ResolverDecisionType; import org.eclipse.buckminster.core.rmap.model.Provider; import org.eclipse.buckminster.core.rmap.model.ProviderScore; import org.eclipse.buckminster.core.rmap.model.SearchPath; import org.eclipse.buckminster.core.rmap.model.URIMatcher; import org.eclipse.buckminster.core.rmap.model.VersionConverterDesc; import org.eclipse.buckminster.core.version.ProviderMatch; import org.eclipse.buckminster.core.version.VersionMatch; import org.eclipse.buckminster.core.version.VersionSelector; import org.eclipse.buckminster.osgi.filter.Filter; import org.eclipse.buckminster.runtime.Buckminster; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.buckminster.sax.Utils; import org.eclipse.buckminster.team.psf.PSF; import org.eclipse.buckminster.team.psf.Project; import org.eclipse.buckminster.team.psf.RepositoryProvider; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.EList; 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.impl.ResourceSetImpl; import org.eclipse.osgi.util.NLS; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; public class PSFProvider extends Provider { public static final String BM_PFS_PROVIDER_NS = XMLConstants.BM_PREFIX + "PSFProvider-1.0"; //$NON-NLS-1$ public static final String BM_PFS_PROVIDER_PREFIX = "psf"; //$NON-NLS-1$ public static final String ATTR_PSF_FILE = "psfFile"; //$NON-NLS-1$ private final String psfFile; public PSFProvider(SearchPath searchPath, String remoteReaderType, String[] componentTypeIDs, VersionConverterDesc versionConverterDesc, Format uri, Format digest, String digestAlgorithm, Filter resolutionFilter, Map<String, String> properties, URIMatcher uriMatcher, Documentation documentation, String pfsFile) { super(searchPath, remoteReaderType, componentTypeIDs, versionConverterDesc, uri, digest, digestAlgorithm, resolutionFilter, properties, uriMatcher, documentation); this.psfFile = pfsFile; } @Override public ProviderMatch findMatch(NodeQuery query, MultiStatus problemCollector, IProgressMonitor monitor) throws CoreException { monitor.beginTask("", 100); //$NON-NLS-1$ try { URI providerURI = URI.createURI(getURI(query.getProperties())); ProviderScore score = query.getProviderScore(isMutable(), hasSource()); if (score == ProviderScore.REJECTED) { String msg = NLS.bind("Provider {0} for {1} score_below_treshold", getReaderTypeId(), providerURI); problemCollector.add(new Status(IStatus.ERROR, CorePlugin.getID(), IStatus.OK, msg, null)); return null; } PSF psf = getPSF(query, problemCollector, MonitorUtils.subMonitor(monitor, 10)); if (psf == null) return null; ComponentRequest cr = query.getComponentRequest(); ProviderMatch found = null; for (RepositoryProvider provider : psf.getProviders()) { IReaderType rt = AbstractReaderType.getTypeForRepositoryProvider(provider.getId()); if (rt == null) { query.logDecision(ResolverDecisionType.READER_TYPE_NOT_FOUND, provider.getId()); continue; } for (Project project : provider.getProjects()) { String ref = project.getReference(); ReferenceInfo refInfo = rt.extractReferenceInfo(ref); String repoLocation = refInfo.getRepositoryLocation(); if (!(cr.getProjectName().equals(refInfo.getProjectName()) || cr.getName().equals(refInfo.getProjectName()))) { // Check if the leaf part of the repository location // contains the name. // int idx = repoLocation.lastIndexOf('/'); if (idx < 0) continue; ++idx; boolean startsWithProjName = repoLocation.indexOf(cr.getProjectName(), idx) == idx; boolean startsWithName = repoLocation.indexOf(cr.getName(), idx) == idx; if (!(startsWithProjName || startsWithName)) continue; if (startsWithProjName) idx += cr.getProjectName().length(); else idx += cr.getName().length(); char endChar = idx < repoLocation.length() ? repoLocation.charAt(idx) : 0; if ((endChar >= '0' && endChar <= '9') || (endChar >= 'A' && endChar <= 'Z') || (endChar >= 'a' && endChar <= 'z') || endChar == '.') continue; } if (!query.isMatch(refInfo.getSelector())) continue; Format uri = new Format(repoLocation); Provider delegated = new Provider(getSearchPath(), rt.getId(), getComponentTypeIDs(), getVersionConverterDesc(), uri, null, null, getResolutionFilter(), getProviderProperties(), null, null); NodeQuery tmpQuery = query; VersionSelector vs = refInfo.getSelector(); if (vs != null && query.getBranchTagPath().length == 0) { ComponentQuery cquery = query.getComponentQuery(); ComponentQueryBuilder cqTmp = new ComponentQueryBuilder(); cqTmp.initFrom(cquery); AdvisorNodeBuilder foundNode = null; for (AdvisorNodeBuilder node : cqTmp.getAdvisoryNodes()) { Pattern pattern = node.getNamePattern(); if (!(pattern == null || pattern.matcher(cr.getName()).find())) continue; String matchingType = node.getComponentTypeID(); if (!(matchingType == null || matchingType.equals(cr.getComponentTypeID()))) continue; Filter filter = node.getFilter(); if (filter == null || filter.matches(query.getContext())) { foundNode = node; break; } } if (foundNode == null) { foundNode = cqTmp.addAdvisorNode(); foundNode.setNamePattern(Pattern.compile(Pattern.quote(cr.getName()))); } foundNode.setBranchTagPath(new VersionSelector[] { vs }); ResolutionContext tmpContext = new ResolutionContext(cqTmp.createComponentQuery(), query.getResolutionContext()); tmpQuery = new NodeQuery(tmpContext, query.getQualifiedDependency()); } ProviderMatch candidate = delegated.findMatch(tmpQuery, problemCollector, monitor); if (candidate == null) continue; if (found == null) found = candidate; else if (found.compareTo(candidate) < 0) { query.logDecision(ResolverDecisionType.MATCH_REJECTED, found.getVersionMatch(), NLS.bind("{0} is a better match", candidate .getVersionMatch())); found = candidate; } } } return found; } finally { monitor.done(); } } public PSF getPSF(NodeQuery query, MultiStatus problemCollector, IProgressMonitor monitor) throws CoreException { monitor.beginTask(null, 700); Map<UUID, Object> userCache = query.getContext().getUserCache(); synchronized (userCache) { PSF psf = getCachedPSF(userCache); if (psf != null) return psf; try { VersionSelector[] btPath = query.getBranchTagPath(); if (btPath.length == 0) psf = getPSF(null, query, MonitorUtils.subMonitor(monitor, 100)); else { CoreException lastException = null; for (VersionSelector bt : btPath) { try { psf = getPSF(bt, query, MonitorUtils.subMonitor(monitor, 100)); lastException = null; } catch (CoreException e) { lastException = e; } } if (lastException != null) throw lastException; } cachePSF(userCache, psf); return psf; } catch (CoreException e) { problemCollector.add(e.getStatus()); Buckminster.getLogger().debug(e.getMessage()); return null; } finally { monitor.done(); } } } @Override protected void addAttributes(AttributesImpl attrs) throws SAXException { super.addAttributes(attrs); attrs.addAttribute(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type", "xsi:type", "CDATA", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ BM_PFS_PROVIDER_PREFIX + ":PDEMapProvider"); //$NON-NLS-1$ if (psfFile != null) Utils.addAttribute(attrs, ATTR_PSF_FILE, psfFile); } private void cachePSF(Map<UUID, Object> userCache, PSF psf) { userCache.put(getId(), psf); } private PSF getCachedPSF(Map<UUID, Object> userCache) { return (PSF) userCache.get(getId()); } private PSF getPSF(VersionSelector vs, NodeQuery query, IProgressMonitor monitor) throws CoreException { ProviderMatch match = new ProviderMatch(this, CorePlugin.getDefault().getComponentType(IComponentType.UNKNOWN), new VersionMatch(null, vs, -1, new Date(), null), ProviderScore.GOOD, query); IComponentReader reader = match.getReader(MonitorUtils.subMonitor(monitor, 10)); IStreamConsumer<PSF> psfReader = new IStreamConsumer<PSF>() { @Override public PSF consumeStream(IComponentReader rdr, String streamName, InputStream stream, IProgressMonitor consumerMon) throws CoreException, IOException { File tempFile = File.createTempFile("bm-", ".psf"); //$NON-NLS-1$ //$NON-NLS-2$ try { OutputStream out = null; try { out = new FileOutputStream(tempFile); IOUtils.copy(stream, out, consumerMon); } finally { IOUtils.close(out); } ResourceSet rs = new ResourceSetImpl(); Resource resource = rs.getResource(URI.createFileURI(tempFile.getAbsolutePath()), true); EList<EObject> content = resource.getContents(); if (content.size() != 1) throw BuckminsterException.fromMessage(NLS.bind("Unable to parse psf file from {0}", streamName)); return (PSF) content.get(0); } finally { tempFile.delete(); } } }; try { if (reader instanceof ICatalogReader) { if (psfFile == null) throw BuckminsterException.fromMessage(NLS.bind("The psfFile attribute is mandatory when using reader of type {0}", getReaderTypeId())); return ((ICatalogReader) reader).readFile(psfFile, psfReader, MonitorUtils.subMonitor(monitor, 100)); } if (psfFile != null) throw BuckminsterException.fromMessage(NLS.bind("The psfFile attribute cannot be used in conjunction with reader of type {0}", getReaderTypeId())); return ((IFileReader) reader).readFile(psfReader, MonitorUtils.subMonitor(monitor, 100)); } catch (IOException e) { throw BuckminsterException.wrap(e); } } }