Index: /trunk/src/org/openstreetmap/josm/io/AbstractParser.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/AbstractParser.java	(revision 6201)
+++ /trunk/src/org/openstreetmap/josm/io/AbstractParser.java	(revision 6201)
@@ -0,0 +1,207 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Date;
+
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.RelationMemberData;
+import org.openstreetmap.josm.data.osm.User;
+import org.openstreetmap.josm.data.osm.history.HistoryNode;
+import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
+import org.openstreetmap.josm.data.osm.history.HistoryRelation;
+import org.openstreetmap.josm.data.osm.history.HistoryWay;
+import org.openstreetmap.josm.tools.DateUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Base class of {@link OsmChangesetContentParser} and {@link OsmHistoryReader} internal parsers.
+ * @since 6201
+ */
+public abstract class AbstractParser extends DefaultHandler {
+    
+    /** the current primitive to be read */
+    protected HistoryOsmPrimitive currentPrimitive;
+    protected Locator locator;
+
+    @Override
+    public void setDocumentLocator(Locator locator) {
+        this.locator = locator;
+    }
+    
+    protected abstract void throwException(String message) throws SAXException;
+
+    protected final long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException {
+        String v = attr.getValue(name);
+        if (v == null) {
+            throwException(tr("Missing mandatory attribute ''{0}''.", name));
+        }
+        Long l = 0L;
+        try {
+            l = Long.parseLong(v);
+        } catch(NumberFormatException e) {
+            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
+        }
+        if (l < 0) {
+            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
+        }
+        return l;
+    }
+
+    protected final Long getAttributeLong(Attributes attr, String name) throws SAXException {
+        String v = attr.getValue(name);
+        if (v == null)
+            return null;
+        Long l = 0L;
+        try {
+            l = Long.parseLong(v);
+        } catch(NumberFormatException e) {
+            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
+        }
+        if (l < 0) {
+            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
+        }
+        return l;
+    }
+
+    protected final Double getAttributeDouble(Attributes attr, String name) throws SAXException {
+        String v = attr.getValue(name);
+        if (v == null) {
+            return null;
+        }
+        double d = 0.0;
+        try {
+            d = Double.parseDouble(v);
+        } catch(NumberFormatException e) {
+            throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
+        }
+        return d;
+    }
+
+    protected final String getMandatoryAttributeString(Attributes attr, String name) throws SAXException {
+        String v = attr.getValue(name);
+        if (v == null) {
+            throwException(tr("Missing mandatory attribute ''{0}''.", name));
+        }
+        return v;
+    }
+
+    protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException {
+        String v = attr.getValue(name);
+        if (v == null) {
+            throwException(tr("Missing mandatory attribute ''{0}''.", name));
+        }
+        if ("true".equals(v)) return true;
+        if ("false".equals(v)) return false;
+        throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
+        return false; // not reached
+    }
+    
+    protected final HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
+        long id = getMandatoryAttributeLong(atts,"id");
+        long version = getMandatoryAttributeLong(atts,"version");
+        long changesetId = getMandatoryAttributeLong(atts,"changeset");
+        boolean visible= getMandatoryAttributeBoolean(atts, "visible");
+
+        Long uid = getAttributeLong(atts, "uid");
+        String userStr = atts.getValue("user");
+        User user;
+        if (userStr != null) {
+            if (uid != null) {
+                user = User.createOsmUser(uid, userStr);
+            } else {
+                user = User.createLocalUser(userStr);
+            }
+        } else {
+            user = User.getAnonymous();
+        }
+
+        String v = getMandatoryAttributeString(atts, "timestamp");
+        Date timestamp = DateUtils.fromString(v);
+        HistoryOsmPrimitive primitive = null;
+        if (type.equals(OsmPrimitiveType.NODE)) {
+            Double lat = getAttributeDouble(atts, "lat");
+            Double lon = getAttributeDouble(atts, "lon");
+            LatLon coor = (lat != null && lon != null) ? new LatLon(lat,lon) : null;
+            primitive = new HistoryNode(
+                    id,version,visible,user,changesetId,timestamp,coor
+            );
+
+        } else if (type.equals(OsmPrimitiveType.WAY)) {
+            primitive = new HistoryWay(
+                    id,version,visible,user,changesetId,timestamp
+            );
+        }if (type.equals(OsmPrimitiveType.RELATION)) {
+            primitive = new HistoryRelation(
+                    id,version,visible,user,changesetId,timestamp
+            );
+        }
+        return primitive;
+    }
+
+    protected final void startNode(Attributes atts) throws SAXException {
+        currentPrimitive = createPrimitive(atts, OsmPrimitiveType.NODE);
+    }
+
+    protected final void startWay(Attributes atts) throws SAXException {
+        currentPrimitive = createPrimitive(atts, OsmPrimitiveType.WAY);
+    }
+    
+    protected final void startRelation(Attributes atts) throws SAXException {
+        currentPrimitive = createPrimitive(atts, OsmPrimitiveType.RELATION);
+    }
+
+    protected final void handleTag(Attributes atts) throws SAXException {
+        String key = getMandatoryAttributeString(atts, "k");
+        String value = getMandatoryAttributeString(atts, "v");
+        currentPrimitive.put(key,value);
+    }
+
+    protected final void handleNodeReference(Attributes atts) throws SAXException {
+        long ref = getMandatoryAttributeLong(atts, "ref");
+        ((HistoryWay)currentPrimitive).addNode(ref);
+    }
+
+    protected void handleMember(Attributes atts) throws SAXException {
+        long ref = getMandatoryAttributeLong(atts, "ref");
+        String v = getMandatoryAttributeString(atts, "type");
+        OsmPrimitiveType type = null;
+        try {
+            type = OsmPrimitiveType.fromApiTypeName(v);
+        } catch(IllegalArgumentException e) {
+            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
+        }
+        String role = getMandatoryAttributeString(atts, "role");
+        RelationMemberData member = new RelationMemberData(role, type,ref);
+        ((HistoryRelation)currentPrimitive).addMember(member);
+    }
+    
+    protected final boolean doStartElement(String qName, Attributes atts) throws SAXException {
+        if (qName.equals("node")) {
+            startNode(atts);
+            return true;
+        } else if (qName.equals("way")) {
+            startWay(atts);
+            return true;
+        } else if (qName.equals("relation")) {
+            startRelation(atts);
+            return true;
+        } else if (qName.equals("tag")) {
+            handleTag(atts);
+            return true;
+        } else if (qName.equals("nd")) {
+            handleNodeReference(atts);
+            return true;
+        } else if (qName.equals("member")) {
+            handleMember(atts);
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java	(revision 6200)
+++ /trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java	(revision 6201)
@@ -9,224 +9,43 @@
 import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
-import java.util.Date;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.ChangesetDataSet;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.data.osm.RelationMemberData;
-import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetModificationType;
-import org.openstreetmap.josm.data.osm.history.HistoryNode;
-import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
-import org.openstreetmap.josm.data.osm.history.HistoryRelation;
-import org.openstreetmap.josm.data.osm.history.HistoryWay;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
-import org.openstreetmap.josm.tools.DateUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
 
 /**
  * Parser for OSM changeset content.
- *
+ * @since 2688
  */
 public class OsmChangesetContentParser {
 
     private InputSource source;
-    private ChangesetDataSet data;
+    private final ChangesetDataSet data = new ChangesetDataSet();
 
-    // FIXME: this class has many similarities with OsmHistoryReader.Parser and should be merged
-    private class Parser extends DefaultHandler {
+    private class Parser extends AbstractParser {
 
-        /** the current primitive to be read */
-        private HistoryOsmPrimitive currentPrimitive;
         /** the current change modification type */
         private ChangesetDataSet.ChangesetModificationType currentModificationType;
 
-        private Locator locator;
-
-        @Override
-        public void setDocumentLocator(Locator locator) {
-            this.locator = locator;
-        }
-
         protected void throwException(String message) throws OsmDataParsingException {
-            throw new OsmDataParsingException(
-                    message
-            ).rememberLocation(locator);
+            throw new OsmDataParsingException(message).rememberLocation(locator);
         }
 
         protected void throwException(Exception e) throws OsmDataParsingException {
-            throw new OsmDataParsingException(
-                    e
-            ).rememberLocation(locator);
-        }
-
-        protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            Long l = 0L;
-            try {
-                l = Long.parseLong(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-
-        protected Long getAttributeLong(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null)
-                return null;
-            Long l = null;
-            try {
-                l = Long.parseLong(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-
-        protected Double getAttributeDouble(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                return null;
-            }
-            double d = 0.0;
-            try {
-                d = Double.parseDouble(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
-            }
-            return d;
-        }
-
-        protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            return v;
-        }
-
-        protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            if ("true".equals(v)) return true;
-            if ("false".equals(v)) return false;
-            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
-            // not reached
-            return false;
-        }
-
-        protected  HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
-            long id = getMandatoryAttributeLong(atts,"id");
-            long version = getMandatoryAttributeLong(atts,"version");
-            long changesetId = getMandatoryAttributeLong(atts,"changeset");
-            boolean visible= getMandatoryAttributeBoolean(atts, "visible");
-
-            Long uid = getAttributeLong(atts, "uid");
-            String userStr = atts.getValue("user");
-            User user;
-            if (userStr != null) {
-                if (uid != null) {
-                    user = User.createOsmUser(uid, userStr);
-                } else {
-                    user = User.createLocalUser(userStr);
-                }
-            } else {
-                user = User.getAnonymous();
-            }
-
-            String v = getMandatoryAttributeString(atts, "timestamp");
-            Date timestamp = DateUtils.fromString(v);
-            HistoryOsmPrimitive primitive = null;
-            if (type.equals(OsmPrimitiveType.NODE)) {
-                Double lat = getAttributeDouble(atts, "lat");
-                Double lon = getAttributeDouble(atts, "lon");
-                LatLon coor = (lat != null && lon != null) ? new LatLon(lat,lon) : null;
-                primitive = new HistoryNode(
-                        id,version,visible,user,changesetId,timestamp,coor
-                );
-
-            } else if (type.equals(OsmPrimitiveType.WAY)) {
-                primitive = new HistoryWay(
-                        id,version,visible,user,changesetId,timestamp
-                );
-            }if (type.equals(OsmPrimitiveType.RELATION)) {
-                primitive = new HistoryRelation(
-                        id,version,visible,user,changesetId,timestamp
-                );
-            }
-            return primitive;
-        }
-
-        protected void startNode(Attributes atts) throws SAXException {
-            currentPrimitive= createPrimitive(atts, OsmPrimitiveType.NODE);
-        }
-
-        protected void startWay(Attributes atts) throws SAXException {
-            currentPrimitive= createPrimitive(atts, OsmPrimitiveType.WAY);
-        }
-        protected void startRelation(Attributes atts) throws SAXException {
-            currentPrimitive= createPrimitive(atts, OsmPrimitiveType.RELATION);
-        }
-
-        protected void handleTag(Attributes atts) throws SAXException {
-            String key= getMandatoryAttributeString(atts, "k");
-            String value= getMandatoryAttributeString(atts, "v");
-            currentPrimitive.put(key,value);
-        }
-
-        protected void handleNodeReference(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            ((HistoryWay)currentPrimitive).addNode(ref);
-        }
-
-        protected void handleMember(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            String v = getMandatoryAttributeString(atts, "type");
-            OsmPrimitiveType type = null;
-            try {
-                type = OsmPrimitiveType.fromApiTypeName(v);
-            } catch(IllegalArgumentException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
-            }
-            String role = getMandatoryAttributeString(atts, "role");
-            RelationMemberData member = new RelationMemberData(role, type,ref);
-            ((HistoryRelation)currentPrimitive).addMember(member);
+            throw new OsmDataParsingException(e).rememberLocation(locator);
         }
 
         @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-            if (qName.equals("node")) {
-                startNode(atts);
-            } else if (qName.equals("way")) {
-                startWay(atts);
-            } else if (qName.equals("relation")) {
-                startRelation(atts);
-            } else if (qName.equals("tag")) {
-                handleTag(atts);
-            } else if (qName.equals("nd")) {
-                handleNodeReference(atts);
-            } else if (qName.equals("member")) {
-                handleMember(atts);
+            if (super.doStartElement(qName, atts)) {
+                // done
             } else if (qName.equals("osmChange")) {
                 // do nothing
@@ -282,26 +101,30 @@
 
     /**
-     * Create a parser
+     * Constructs a new {@code OsmChangesetContentParser}.
      *
      * @param source the input stream with the changeset content as XML document. Must not be null.
-     * @throws IllegalArgumentException thrown if source is null.
+     * @throws UnsupportedEncodingException if {@code UTF-8} charset is missing
+     * @throws IllegalArgumentException if source is {@code null}.
      */
     public OsmChangesetContentParser(InputStream source) throws UnsupportedEncodingException {
         CheckParameterUtil.ensureParameterNotNull(source, "source");
         this.source = new InputSource(new InputStreamReader(source, "UTF-8"));
-        data = new ChangesetDataSet();
     }
 
+    /**
+     * Constructs a new {@code OsmChangesetContentParser}.
+     *
+     * @param source the input stream with the changeset content as XML document. Must not be null.
+     * @throws IllegalArgumentException if source is {@code null}.
+     */
     public OsmChangesetContentParser(String source) {
         CheckParameterUtil.ensureParameterNotNull(source, "source");
         this.source = new InputSource(new StringReader(source));
-        data = new ChangesetDataSet();
     }
 
     /**
-     * Parses the content
+     * Parses the content.
      *
-     * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE}
-     * if null
+     * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
      * @return the parsed data
      * @throws OsmDataParsingException thrown if something went wrong. Check for chained
Index: /trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java	(revision 6200)
+++ /trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java	(revision 6201)
@@ -7,25 +7,16 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.Date;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.data.osm.RelationMemberData;
-import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
-import org.openstreetmap.josm.data.osm.history.HistoryNode;
 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
-import org.openstreetmap.josm.data.osm.history.HistoryRelation;
-import org.openstreetmap.josm.data.osm.history.HistoryWay;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.tools.DateUtils;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
 
 /**
@@ -35,5 +26,5 @@
  * {@link org.openstreetmap.josm.data.osm.OsmPrimitive}s. We use objects derived from
  * {@link HistoryOsmPrimitive} instead and we keep the data in a dedicated {@link HistoryDataSet}.
- *
+ * @since 1670
  */
 public class OsmHistoryReader {
@@ -42,15 +33,5 @@
     private final HistoryDataSet data;
 
-    // FIXME: this class has many similarities with OsmChangesetContentParser.Parser and should be merged
-    private class Parser extends DefaultHandler {
-
-        /** the current primitive to be read */
-        private HistoryOsmPrimitive current;
-        private Locator locator;
-
-        @Override
-        public void setDocumentLocator(Locator locator) {
-            this.locator = locator;
-        }
+    private class Parser extends AbstractParser {
 
         protected String getCurrentPosition() {
@@ -61,167 +42,10 @@
 
         protected void throwException(String message) throws SAXException {
-            throw new SAXException(
-                    getCurrentPosition()
-                    +   message
-            );
+            throw new SAXException(getCurrentPosition() + message);
         }
 
-        protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            Long l = 0L;
-            try {
-                l = Long.parseLong(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-
-        protected Long getAttributeLong(Attributes attr, String name) throws SAXException {
-            String v = attr.getValue(name);
-            if (v == null)
-                return null;
-            Long l = null;
-            try {
-                l = Long.parseLong(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-
-        protected Double getAttributeDouble(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                return null;
-            }
-            double d = 0.0;
-            try {
-                d = Double.parseDouble(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
-            }
-            return d;
-        }
-
-        protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            return v;
-        }
-
-        protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            if ("true".equals(v)) return true;
-            if ("false".equals(v)) return false;
-            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
-            // not reached
-            return false;
-        }
-
-        protected  HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
-            long id = getMandatoryAttributeLong(atts,"id");
-            long version = getMandatoryAttributeLong(atts,"version");
-            long changesetId = getMandatoryAttributeLong(atts,"changeset");
-            boolean visible= getMandatoryAttributeBoolean(atts, "visible");
-            Long uid = getAttributeLong(atts, "uid");
-            String userStr = atts.getValue("user");
-            User user;
-            if (userStr != null) {
-                if (uid != null) {
-                    user = User.createOsmUser(uid, userStr);
-                } else {
-                    user = User.createLocalUser(userStr);
-                }
-            } else {
-                user = User.getAnonymous();
-            }
-            String v = getMandatoryAttributeString(atts, "timestamp");
-            Date timestamp = DateUtils.fromString(v);
-            HistoryOsmPrimitive primitive = null;
-            if (type.equals(OsmPrimitiveType.NODE)) {
-                Double lat = getAttributeDouble(atts, "lat");
-                Double lon = getAttributeDouble(atts, "lon");
-                LatLon coord = (lat != null && lon != null) ? new LatLon(lat,lon) : null;
-                primitive = new HistoryNode(
-                        id,version,visible,user,changesetId,timestamp,coord
-                );
-
-            } else if (type.equals(OsmPrimitiveType.WAY)) {
-                primitive = new HistoryWay(
-                        id,version,visible,user,changesetId,timestamp
-                );
-            }if (type.equals(OsmPrimitiveType.RELATION)) {
-                primitive = new HistoryRelation(
-                        id,version,visible,user,changesetId,timestamp
-                );
-            }
-            return primitive;
-        }
-
-        protected void startNode(Attributes atts) throws SAXException {
-            current= createPrimitive(atts, OsmPrimitiveType.NODE);
-        }
-
-        protected void startWay(Attributes atts) throws SAXException {
-            current= createPrimitive(atts, OsmPrimitiveType.WAY);
-        }
-        protected void startRelation(Attributes atts) throws SAXException {
-            current= createPrimitive(atts, OsmPrimitiveType.RELATION);
-        }
-
-        protected void handleTag(Attributes atts) throws SAXException {
-            String key= getMandatoryAttributeString(atts, "k");
-            String value= getMandatoryAttributeString(atts, "v");
-            current.put(key,value);
-        }
-
-        protected void handleNodeReference(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            ((HistoryWay)current).addNode(ref);
-        }
-
-        protected void handleMember(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            String v = getMandatoryAttributeString(atts, "type");
-            OsmPrimitiveType type = null;
-            try {
-                type = OsmPrimitiveType.fromApiTypeName(v);
-            } catch(IllegalArgumentException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
-            }
-            String role = getMandatoryAttributeString(atts, "role");
-            RelationMemberData member = new RelationMemberData(role, type,ref);
-            ((HistoryRelation)current).addMember(member);
-        }
-
-        @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-            if (qName.equals("node")) {
-                startNode(atts);
-            } else if (qName.equals("way")) {
-                startWay(atts);
-            } else if (qName.equals("relation")) {
-                startRelation(atts);
-            } else if (qName.equals("tag")) {
-                handleTag(atts);
-            } else if (qName.equals("nd")) {
-                handleNodeReference(atts);
-            } else if (qName.equals("member")) {
-                handleMember(atts);
-            }
+        @Override
+        public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+            doStartElement(qName, atts);
         }
 
@@ -231,14 +55,28 @@
                     || qName.equals("way")
                     || qName.equals("relation")) {
-                data.put(current);
+                data.put(currentPrimitive);
             }
         }
     }
 
+    /**
+     * Constructs a new {@code OsmHistoryReader}.
+     *
+     * @param source the input stream with the history content as XML document. Must not be null.
+     * @throws IllegalArgumentException if source is {@code null}.
+     */
     public OsmHistoryReader(InputStream source) {
+        CheckParameterUtil.ensureParameterNotNull(source, "source");
         this.in = source;
         this.data = new HistoryDataSet();
     }
 
+    /**
+     * Parses the content.
+     * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
+     * @return the parsed data
+     * @throws SAXException If any SAX errors occur during processing.
+     * @throws IOException If any IO errors occur.
+     */
     public HistoryDataSet parse(ProgressMonitor progressMonitor) throws SAXException, IOException {
         InputSource inputSource = new InputSource(new InputStreamReader(in, "UTF-8"));
@@ -246,7 +84,7 @@
         try {
             SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
-        } catch (ParserConfigurationException e1) {
-            e1.printStackTrace(); // broken SAXException chaining
-            throw new SAXException(e1);
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace(); // broken SAXException chaining
+            throw new SAXException(e);
         } finally {
             progressMonitor.finishTask();
