// 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);
}
}
}
}