/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package com.bc.ceres.core.runtime.internal; import com.bc.ceres.core.Assert; import com.bc.ceres.core.ProgressMonitor; import com.bc.ceres.core.SubProgressMonitor; import com.bc.ceres.core.CoreException; import com.bc.ceres.core.CanceledException; import com.bc.ceres.core.runtime.Constants; import com.bc.ceres.core.runtime.Module; import com.bc.ceres.core.runtime.ProxyConfig; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StreamTokenizer; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; public class RepositoryScanner { private Logger logger; private URL url; private ProxyConfig proxyConfig; public RepositoryScanner(Logger logger, URL url, ProxyConfig proxyConfig) { Assert.notNull(logger, "logger"); Assert.notNull(url, "url"); Assert.notNull(proxyConfig, "proxyConfig"); this.logger = logger; this.url = url; this.proxyConfig = proxyConfig; } public Module[] scan(ProgressMonitor progressMonitor) throws CoreException { try { Assert.notNull(progressMonitor, "progressMonitor"); return scanImpl(progressMonitor); } catch (IOException e) { throw new CoreException(e); } } private Module[] scanImpl(ProgressMonitor progressMonitor) throws IOException, CanceledException { List<Module> repositoryModules = new ArrayList<Module>(64); progressMonitor.beginTask("Retrieving module information from repository", 100); progressMonitor.setSubTaskName("Connecting..."); final URLConnection urlConnection; if (url.getProtocol().equalsIgnoreCase("http")) { urlConnection = UrlHelper.openConnection(url, proxyConfig, "GET"); } else { urlConnection = url.openConnection(); } progressMonitor.worked(10); final InputStream inputStream = urlConnection.getInputStream(); final InputStreamReader reader = new InputStreamReader(inputStream); try { String[] hrefs; progressMonitor.setSubTaskName("Scanning..."); if ("text/plain".equals(urlConnection.getContentType())) { hrefs = parseTextPlain(reader); } else { hrefs = parseTextHtml(reader); } progressMonitor.worked(10); if (hrefs.length > 0) { collectModules(hrefs, repositoryModules, SubProgressMonitor.create(progressMonitor, 80)); } else { progressMonitor.worked(80); } } finally { reader.close(); progressMonitor.done(); } return repositoryModules.toArray(new Module[repositoryModules.size()]); } private void collectModules(String[] hrefs, List<Module> repositoryModules, ProgressMonitor pm) throws CanceledException { pm.beginTask("Loading modules...", hrefs.length); try { for (String href : hrefs) { if (pm.isCanceled()) { throw new CanceledException(); } collectModule(href, repositoryModules); pm.worked(1); } } finally { pm.done(); } } private void collectModule(String href, List<Module> repositoryModules) { if (href.startsWith("http:")) { return; } String moduleName = href; if (moduleName.startsWith("/")) { moduleName = moduleName.substring(1); } if (moduleName.endsWith("/")) { moduleName = moduleName.substring(0, moduleName.length() - 1); } String urlString = url.toExternalForm(); if (!urlString.endsWith("/")) { urlString += "/"; } String urlBase = urlString + moduleName + '/'; final ModuleImpl module; try { URL manifestUrl = new URL(urlBase + Constants.MODULE_MANIFEST_NAME ); module = new ModuleReader(logger).readFromManifest(manifestUrl, proxyConfig); } catch (CoreException e) { logger.warning(String.format("Repository entry [%s] is invalid: %s", moduleName, e.getMessage())); return; } catch (MalformedURLException e) { logger.warning(String.format("Repository entry [%s] is invalid: %s", moduleName, e.getMessage())); return; } Module repositoryModule = createRepositoryModule(module, urlBase, moduleName + ".jar"); if (repositoryModule == null) { repositoryModule = createRepositoryModule(module, urlBase, moduleName + ".zip"); } if (repositoryModule == null) { logger.warning(String.format("Repository entry [%s] is invalid, no archive found.", moduleName)); return; } logger.info(String.format("Repository entry [%s] found.", moduleName)); repositoryModules.add(repositoryModule); } private Module createRepositoryModule(ModuleImpl module, String urlBase, String archiveName) { URL archiveUrl; URLConnection urlConnection; try { archiveUrl = new URL(urlBase + archiveName); urlConnection = UrlHelper.openConnection(archiveUrl, proxyConfig, "HEAD"); urlConnection.connect(); } catch (IOException e) { return null; } int contentLength = urlConnection.getContentLength(); long lastModified = urlConnection.getLastModified(); String aboutUrlString = urlBase + "about.html"; if (!UrlHelper.existsResource(aboutUrlString, proxyConfig)) { aboutUrlString = null; } module.setLocation(archiveUrl); module.setContentLength(contentLength); module.setLastModified(lastModified); module.setAboutUrl(aboutUrlString); return module; } private static String[] parseTextHtml(InputStreamReader reader) throws IOException { return new HrefParser(reader).parse(); } private static String[] parseTextPlain(InputStreamReader reader) throws IOException { StreamTokenizer st = new StreamTokenizer(reader); st.resetSyntax(); st.whitespaceChars(0, 32); st.wordChars(33, 255); st.eolIsSignificant(false); ArrayList<String> list = new ArrayList<String>(32); while (true) { int type = st.nextToken(); if (type == StreamTokenizer.TT_EOF) { break; } list.add(st.sval); } return list.toArray(new String[list.size()]); } }