// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.opendata.core.io; import static org.openstreetmap.josm.tools.I18n.tr; import java.io.File; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.gui.progress.ProgressMonitor; import org.openstreetmap.josm.io.AbstractReader; import org.openstreetmap.josm.io.OsmServerReader; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.plugins.opendata.core.OdConstants; import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler; import org.openstreetmap.josm.plugins.opendata.core.io.archive.ArchiveReader; import org.openstreetmap.josm.plugins.opendata.core.io.archive.SevenZipReader; import org.openstreetmap.josm.plugins.opendata.core.io.archive.ZipReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GmlReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.KmlReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.KmzReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpReader; import org.openstreetmap.josm.plugins.opendata.core.io.geographic.TabReader; import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvReader; import org.openstreetmap.josm.plugins.opendata.core.io.tabular.OdsReader; import org.openstreetmap.josm.plugins.opendata.core.io.tabular.XlsReader; import org.openstreetmap.josm.tools.CheckParameterUtil; public class NetworkReader extends OsmServerReader { private final String url; private final AbstractDataSetHandler handler; private Class<? extends AbstractReader> readerClass; private final boolean promptUser; private File file; private String filename; /** * File readers */ public static final Map<String, Class<? extends AbstractReader>> FILE_READERS = new HashMap<>(); static { FILE_READERS.put(OdConstants.CSV_EXT, CsvReader.class); FILE_READERS.put(OdConstants.KML_EXT, KmlReader.class); FILE_READERS.put(OdConstants.KMZ_EXT, KmzReader.class); FILE_READERS.put(OdConstants.GML_EXT, GmlReader.class); FILE_READERS.put(OdConstants.XLS_EXT, XlsReader.class); FILE_READERS.put(OdConstants.ODS_EXT, OdsReader.class); FILE_READERS.put(OdConstants.SHP_EXT, ShpReader.class); FILE_READERS.put(OdConstants.MIF_EXT, MifReader.class); FILE_READERS.put(OdConstants.TAB_EXT, TabReader.class); } public static final Map<String, Class<? extends AbstractReader>> FILE_AND_ARCHIVE_READERS = new HashMap<>(FILE_READERS); static { FILE_AND_ARCHIVE_READERS.put(OdConstants.ZIP_EXT, ZipReader.class); FILE_AND_ARCHIVE_READERS.put(OdConstants.SEVENZIP_EXT, SevenZipReader.class); } public NetworkReader(String url, AbstractDataSetHandler handler, boolean promptUser) { CheckParameterUtil.ensureParameterNotNull(url, "url"); this.url = url; this.handler = handler; this.readerClass = null; this.promptUser = promptUser; } public final File getReadFile() { return file; } public final String getReadFileName() { return filename; } private Class<? extends AbstractReader> findReaderByAttachment() { String cdisp = this.activeConnection.getResponse().getHeaderField("Content-disposition"); if (cdisp != null) { Matcher m = Pattern.compile("attachment;.?filename=(.*)").matcher(cdisp); if (m.matches()) { filename = m.group(1); return findReaderByExtension(filename); } } return null; } private Class<? extends AbstractReader> findReaderByContentType() { String contentType = this.activeConnection.getResponse().getContentType(); if (contentType.startsWith("application/zip")) { return ZipReader.class; } else if (contentType.startsWith("application/x-7z-compressed")) { return SevenZipReader.class; } else if (contentType.startsWith("application/vnd.ms-excel")) { return XlsReader.class; } else if (contentType.startsWith("application/octet-stream")) { //return OdsReader.class;//FIXME, can be anything } else if (contentType.startsWith("text/csv")) { return CsvReader.class; } else if (contentType.startsWith("text/plain")) { //TODO: extract charset return CsvReader.class; } else if (contentType.startsWith("tdyn/html")) { //return CsvReader.class;//FIXME, can also be .tar.gz } else { Main.warn("Unsupported content type: "+contentType); } return null; } private Class<? extends AbstractReader> findReaderByExtension(String filename) { filename = filename.replace("\"", "").toLowerCase(); for (String ext : FILE_AND_ARCHIVE_READERS.keySet()) { if (filename.endsWith("."+ext)) { return FILE_AND_ARCHIVE_READERS.get(ext); } } return null; } @Override public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException { InputStream in = null; ProgressMonitor instance = null; try { in = getInputStreamRaw(url, progressMonitor); if (in == null) return null; progressMonitor.subTask(tr("Downloading data...")); if (readerClass == null) { readerClass = findReaderByAttachment(); } if (readerClass == null) { readerClass = findReaderByExtension(url); } if (readerClass == null) { readerClass = findReaderByContentType(); } if (readerClass == null) { throw new OsmTransferException("Cannot find appropriate reader !"); //TODO handler job ? } else if (findReaderByExtension(url) != null) { filename = url.substring(url.lastIndexOf('/')+1); } instance = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); if (readerClass.equals(ZipReader.class) || readerClass.equals(SevenZipReader.class)) { ArchiveReader zipReader = readerClass.equals(ZipReader.class) ? new ZipReader(in, handler, promptUser) : new SevenZipReader(in, handler, promptUser); DataSet ds = zipReader.parseDoc(instance); file = zipReader.getReadFile(); return ds; } else if (readerClass.equals(KmlReader.class)) { return KmlReader.parseDataSet(in, instance); } else if (readerClass.equals(KmzReader.class)) { return KmzReader.parseDataSet(in, instance); } else if (readerClass.equals(MifReader.class)) { return MifReader.parseDataSet(in, null, handler, instance); } else if (readerClass.equals(ShpReader.class)) { return ShpReader.parseDataSet(in, null, handler, instance); } else if (readerClass.equals(TabReader.class)) { return TabReader.parseDataSet(in, null, handler, instance); } else if (readerClass.equals(CsvReader.class)) { return CsvReader.parseDataSet(in, handler, instance); } else if (readerClass.equals(OdsReader.class)) { return OdsReader.parseDataSet(in, handler, instance); } else if (readerClass.equals(XlsReader.class)) { return XlsReader.parseDataSet(in, handler, instance); } else if (readerClass.equals(GmlReader.class)) { return GmlReader.parseDataSet(in, handler, instance); } else { throw new IllegalArgumentException("Unsupported reader class: "+readerClass.getName()); } } catch (OsmTransferException e) { throw e; } catch (Exception e) { if (cancel) return null; throw new OsmTransferException(e); } finally { progressMonitor.finishTask(); try { activeConnection = null; if (in != null) { in.close(); } } catch (Exception e) { Main.trace(e); } } } }