Index: /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java
===================================================================
--- /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 33612)
+++ /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 33613)
@@ -63,5 +63,5 @@
             instance = this;
         } else {
-            throw new IllegalAccessError("Cannot instantiate plugin twice !");
+            throw new IllegalStateException("Cannot instantiate plugin twice !");
         }
         // Allow JOSM to import more files
Index: /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/MifTabImporter.java
===================================================================
--- /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/MifTabImporter.java	(revision 33612)
+++ /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/MifTabImporter.java	(revision 33613)
@@ -33,5 +33,5 @@
                 return TabReader.parseDataSet(in, file, handler, instance);
             }
-        } catch (IOException e) {
+        } catch (IOException | IllegalArgumentException e) {
             throw new IllegalDataException(e);
         }
Index: /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabFiles.java
===================================================================
--- /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabFiles.java	(revision 33613)
+++ /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabFiles.java	(revision 33613)
@@ -0,0 +1,160 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.opendata.core.io.geographic;
+
+import static org.geotools.data.shapefile.files.ShpFileType.SHP;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.geotools.data.DataUtilities;
+import org.geotools.data.shapefile.files.ShpFileType;
+import org.geotools.data.shapefile.files.ShpFiles;
+import org.openstreetmap.josm.tools.JosmRuntimeException;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Extension of {@link ShpFiles} class modified to fit MapInfo TAB needs.
+ */
+public class TabFiles extends ShpFiles {
+
+    /**
+     * The urls for each type of file that is associated with the shapefile. The
+     * key is the type of file
+     */
+    private final Map<ShpFileType, URL> urls;
+
+    ////////////////////////////////////////////////////
+
+    @SuppressWarnings("unchecked")
+    public TabFiles(File headerFile, File dataFile) throws IllegalArgumentException {
+        super(fakeShpFile(headerFile)); // Useless but necessary
+
+        try {
+            Field furls = ShpFiles.class.getDeclaredField("urls");
+            Utils.setObjectsAccessible(furls);
+            urls = (Map<ShpFileType, URL>) furls.get(this);
+        } catch (ReflectiveOperationException e) {
+            throw new JosmRuntimeException(e);
+        }
+
+        init(DataUtilities.fileToURL(headerFile));
+        urls.put(ShpFileType.DBF, DataUtilities.fileToURL(dataFile));
+    }
+
+    /**
+     * Used only to give a fake shp file to ShpFiles constructor to avoid IllegalArgument at initialization.
+     */
+    private static URL fakeShpFile(File headerFile) {
+        return DataUtilities.fileToURL(new File(headerFile.getAbsolutePath()+".shp"));
+    }
+
+    private String baseName(Object obj) {
+        if (obj instanceof URL) {
+            return toBase(((URL) obj).toExternalForm());
+        }
+        return null;
+    }
+
+    private String toBase(String path) {
+        return path.substring(0, path.toLowerCase().lastIndexOf(".tab"));
+    }
+
+    ////////////////////////////////////////////////////
+
+    private void init(URL url) {
+        String base = baseName(url);
+        if (base == null) {
+            throw new IllegalArgumentException(
+                    url.getPath()
+                            + " is not one of the files types that is known to be associated with a MapInfo TAB file");
+        }
+
+        String urlString = url.toExternalForm();
+        char lastChar = urlString.charAt(urlString.length()-1);
+        boolean upperCase = Character.isUpperCase(lastChar);
+
+        for (ShpFileType type : ShpFileType.values()) {
+
+            String extensionWithPeriod = type.extensionWithPeriod;
+            if (upperCase) {
+                extensionWithPeriod = extensionWithPeriod.toUpperCase();
+            } else {
+                extensionWithPeriod = extensionWithPeriod.toLowerCase();
+            }
+
+            URL newURL;
+            String string = base + extensionWithPeriod;
+            try {
+                newURL = new URL(url, string);
+            } catch (MalformedURLException e) {
+                // shouldn't happen because the starting url was constructable
+                throw new RuntimeException(e);
+            }
+            urls.put(type, newURL);
+        }
+
+        // if the files are local check each file to see if it exists
+        // if not then search for a file of the same name but try all combinations of the
+        // different cases that the extension can be made up of.
+        // IE Shp, SHP, Shp, ShP etc...
+        if (isLocal()) {
+            Set<Entry<ShpFileType, URL>> entries = urls.entrySet();
+            Map<ShpFileType, URL> toUpdate = new HashMap<>();
+            for (Entry<ShpFileType, URL> entry : entries) {
+                if (!exists(entry.getKey())) {
+                    url = findExistingFile(entry.getKey(), entry.getValue());
+                    if (url != null) {
+                        toUpdate.put(entry.getKey(), url);
+                    }
+                }
+            }
+            urls.putAll(toUpdate);
+        }
+    }
+
+    private URL findExistingFile(ShpFileType shpFileType, URL value) {
+        final File file = DataUtilities.urlToFile(value);
+        File directory = file.getParentFile();
+        if (directory != null && directory.exists()) {
+            File[] files = directory.listFiles((FilenameFilter) (dir, name) -> file.getName().equalsIgnoreCase(name));
+            if (files.length > 0) {
+                try {
+                    return files[0].toURI().toURL();
+                } catch (MalformedURLException e) {
+                    Logging.error(e);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This verifies that this class has been closed correctly (nothing locking)
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        dispose();
+    }
+
+    @Override
+    public String getTypeName() {
+        String path = SHP.toBase(urls.get(SHP));
+        int slash = Math.max(0, path.lastIndexOf('/') + 1);
+        int dot = path.indexOf('.', slash);
+
+        if (dot < 0) {
+            dot = path.length();
+        }
+
+        return path.substring(slash, dot);
+    }
+}
Index: /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java
===================================================================
--- /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java	(revision 33612)
+++ /applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java	(revision 33613)
@@ -15,5 +15,4 @@
 import org.geotools.data.shapefile.dbf.DbaseFileReader;
 import org.geotools.data.shapefile.dbf.DbaseFileReader.Row;
-import org.geotools.data.shapefile.files.TabFiles;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
Index: /applications/editors/josm/plugins/opendata/test/data/regress/15159/Sanisette.tab
===================================================================
--- /applications/editors/josm/plugins/opendata/test/data/regress/15159/Sanisette.tab	(revision 33613)
+++ /applications/editors/josm/plugins/opendata/test/data/regress/15159/Sanisette.tab	(revision 33613)
@@ -0,0 +1,17 @@
+!table
+!version 300
+!charset WindowsLatin1
+
+Definition Table
+  Type NATIVE Charset "WindowsLatin1"
+  Fields 10
+    numero Char (50) ;
+    type Char (50) ;
+    PMR Logical ;
+    adresse Char (50) ;
+    emplacement_valide Char (5) ;
+    INSEE Char (5) ;
+    X_CC43 Decimal (11, 3) ;
+    Y_CC43 Decimal (11, 3) ;
+    X_WGS84 Decimal (6, 3) ;
+    Y_WGS84 Decimal (6, 3) ;
Index: /applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReaderTest.java
===================================================================
--- /applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReaderTest.java	(revision 33613)
+++ /applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReaderTest.java	(revision 33613)
@@ -0,0 +1,40 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.opendata.core.io.geographic;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLStreamException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.plugins.opendata.core.io.NonRegFunctionalTests;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Unit tests of {@link TabReader} class.
+ */
+public class TabReaderTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    public JOSMTestRules rules = new JOSMTestRules().preferences().projection().timeout(60000);
+
+    /**
+     * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/15159">#15159</a>
+     * @throws IOException if an error occurs during reading
+     */
+    @Test
+    public void testTicket15159() throws IOException, XMLStreamException, FactoryConfigurationError {
+        File file = new File(TestUtils.getRegressionDataFile(15159, "Sanisette.tab"));
+        try (InputStream is = new FileInputStream(file)) {
+            NonRegFunctionalTests.testGeneric("#15159", TabReader.parseDataSet(is, file, null, null));
+        }
+    }
+}
