package org.eclipse.buckminster.subversion; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.regex.Pattern; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.RMContext; import org.eclipse.buckminster.core.helpers.FileHandle; import org.eclipse.buckminster.core.reader.AbstractRemoteReader; import org.eclipse.buckminster.core.reader.IReaderType; 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.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.Logger; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.osgi.util.NLS; public abstract class GenericRemoteReader<SVNENTRY, REVISION> extends AbstractRemoteReader { protected final ISubversionSession<SVNENTRY, REVISION> session; private final SVNENTRY[] topEntries; protected GenericRemoteReader(IReaderType readerType, ProviderMatch provider, IProgressMonitor monitor) throws CoreException { super(readerType, provider); VersionMatch vm = provider.getVersionMatch(); VersionSelector branchOrTag = vm.getBranchOrTag(); session = getSession(provider.getRepositoryURI(), branchOrTag, vm.getNumericRevision(), vm.getTimestamp(), provider.getNodeQuery() .getContext()); topEntries = getTopEntries(monitor); if (topEntries.length == 0) throw BuckminsterException.fromMessage(NLS.bind(Messages.unable_to_find_artifacts_at_0, session)); } @Override final public void close() { session.close(); } @Override final public String toString() { return session.toString(); } abstract protected void fetchRemoteFile(URI url, REVISION revision, OutputStream output, IProgressMonitor subMonitor) throws Exception; /** * Implemented by subclasses. Used to retrieve a particular a concrete * session instance. * * @param repositoryURI * @param branchOrTag * @param revision * @param timestamp * @param context * @return * @throws CoreException */ protected abstract ISubversionSession<SVNENTRY, REVISION> getSession(String repositoryURI, VersionSelector branchOrTag, long revision, Date timestamp, RMContext context) throws CoreException; abstract protected SVNENTRY[] getTopEntries(IProgressMonitor monitor) throws CoreException; @Override final protected FileHandle innerGetContents(String fileName, IProgressMonitor monitor) throws CoreException, IOException { Logger logger = CorePlugin.getLogger(); IPath path = Path.fromPortableString(fileName); String topEntry = path.segment(0); boolean found = false; for (SVNENTRY dirEntry : topEntries) { if (topEntry.equals(session.getSvnEntryHelper().getEntryPath(dirEntry))) { found = true; break; } } URI url = session.getSVNUrl(fileName); String key = storeInCache(fileName); if (!found) throw new FileNotFoundException(key); // now copying file to temporary file OutputStream output = null; File destFile = null; try { logger.debug("Reading remote file %s", key); //$NON-NLS-1$ destFile = createTempFile(); output = new FileOutputStream(destFile); final REVISION revision = session.getRevision(); fetchRemoteFile(url, revision, output, MonitorUtils.subMonitor(monitor, 10)); IOUtils.close(output); if (destFile.length() == 0) { // Suspect file not found if (!remoteFileExists(url, revision, monitor)) { logger.debug("Remote file not found: %s", key); //$NON-NLS-1$ throw new FileNotFoundException(url.toString()); } } final FileHandle fh = new FileHandle(fileName, destFile, true); destFile = null; return fh; } catch (CoreException e) { throw e; } catch (IOException e) { throw e; } catch (OperationCanceledException e) { throw e; } catch (Exception e) { final Throwable rootCause = SvnExceptionHandler.getRootCause(e); if (SvnExceptionHandler.hasSvnException(rootCause)) { logger.debug("Remote file not found: %s", key); //$NON-NLS-1$ throw new FileNotFoundException(key); } if (e instanceof RuntimeException) throw (RuntimeException) e; IOException ioe = new IOException(rootCause.getMessage()); ioe.initCause(rootCause); throw ioe; } finally { IOUtils.close(output); if (destFile != null) destFile.delete(); monitor.done(); } } @Override final protected void innerGetMatchingRootFiles(Pattern pattern, List<FileHandle> files, IProgressMonitor monitor) throws CoreException, IOException { ArrayList<String> names = null; ISvnEntryHelper<SVNENTRY> helper = session.getSvnEntryHelper(); for (SVNENTRY dirEntry : topEntries) { final String fileName = helper.getEntryPath(dirEntry); if (pattern.matcher(fileName).matches()) { if (names == null) names = new ArrayList<String>(); names.add(fileName); } } if (names == null) return; if (names.size() == 1) files.add(innerGetContents(names.get(0), monitor)); else { monitor.beginTask(null, names.size() * 100); for (String name : names) files.add(innerGetContents(name, MonitorUtils.subMonitor(monitor, 100))); monitor.done(); } } @Override final protected void innerList(List<String> files, IProgressMonitor monitor) throws CoreException { ISvnEntryHelper<SVNENTRY> helper = session.getSvnEntryHelper(); for (SVNENTRY dirEntry : topEntries) { String fileName = helper.getEntryPath(dirEntry); if (helper.getEntryKind(dirEntry) == ISvnEntryHelper.DIR && !fileName.endsWith("/")) //$NON-NLS-1$ fileName = fileName + '/'; files.add(fileName); } } abstract protected boolean remoteFileExists(URI url, REVISION revision, IProgressMonitor monitor) throws CoreException; abstract protected String storeInCache(String fileName) throws CoreException; }