Index: trunk/src/org/openstreetmap/josm/data/APIDataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/APIDataSet.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/APIDataSet.java	(revision 4100)
@@ -24,4 +24,5 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -286,8 +287,8 @@
     public void adjustRelationUploadOrder() throws CyclicUploadDependencyException{
         LinkedList<OsmPrimitive> newToAdd = new LinkedList<OsmPrimitive>();
-        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Node.class));
-        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Way.class));
-
-        List<Relation> relationsToAdd = OsmPrimitive.getFilteredList(toAdd, Relation.class);
+        newToAdd.addAll(Utils.filteredCollection(toAdd, Node.class));
+        newToAdd.addAll(Utils.filteredCollection(toAdd, Way.class));
+
+        List<Relation> relationsToAdd = new ArrayList<Relation>(Utils.filteredCollection(toAdd, Relation.class));
         List<Relation> noProblemRelations = filterRelationsNotReferringToNewRelations(relationsToAdd);
         newToAdd.addAll(noProblemRelations);
Index: trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 4100)
@@ -10,4 +10,5 @@
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -163,4 +164,5 @@
      * @see #isUndeleted()
      */
+    @Override
     public boolean isNewOrUndeleted() {
         return (id <= 0) || ((flags & (FLAG_VISIBLE + FLAG_DELETED)) == 0);
@@ -261,4 +263,5 @@
      * @return the unique primitive id for this primitive
      */
+    @Override
     public PrimitiveId getPrimitiveId() {
         return new SimplePrimitiveId(getUniqueId(), getType());
@@ -638,3 +641,49 @@
     abstract protected void keysChangedImpl(Map<String, String> originalKeys);
     
+    /**
+     * Replies the name of this primitive. The default implementation replies the value
+     * of the tag <tt>name</tt> or null, if this tag is not present.
+     *
+     * @return the name of this primitive
+     */
+    @Override
+    public String getName() {
+        return get("name");
+    }
+
+    /**
+     * Replies the a localized name for this primitive given by the value of the tags (in this order)
+     * <ul>
+     *   <li>name:lang_COUNTRY_Variant  of the current locale</li>
+     *   <li>name:lang_COUNTRY of the current locale</li>
+     *   <li>name:lang of the current locale</li>
+     *   <li>name of the current locale</li>
+     * </ul>
+     *
+     * null, if no such tag exists
+     *
+     * @return the name of this primitive
+     */
+    @Override
+    public String getLocalName() {
+        String key = "name:" + Locale.getDefault().toString();
+        if (get(key) != null)
+            return get(key);
+        key = "name:" + Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
+        if (get(key) != null)
+            return get(key);
+        key = "name:" + Locale.getDefault().getLanguage();
+        if (get(key) != null)
+            return get(key);
+        return getName();
+    }
+    
+    /**
+     * Replies the display name of a primitive formatted by <code>formatter</code>
+     *
+     * @return the display name
+     */
+    @Override
+    public abstract String getDisplayName(NameFormatter formatter);
+
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 4100)
@@ -3,4 +3,6 @@
 
 import java.util.Date;
+
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 
 /**
@@ -16,5 +18,7 @@
     void setDeleted(boolean deleted);
     boolean isIncomplete();
+    boolean isNewOrUndeleted();
     long getId();
+    PrimitiveId getPrimitiveId();
     int getVersion();
     void setOsmId(long id, int version);
@@ -26,4 +30,9 @@
     int getChangesetId();
     void setChangesetId(int changesetId);
+    
+    void visit(PrimitiveVisitor visitor);
+    String getName();
+    String getLocalName();
+    String getDisplayName(NameFormatter formatter);
 
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/IWay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/IWay.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/IWay.java	(revision 4100)
@@ -6,4 +6,5 @@
     int getNodesCount();
     long getNodeId(int idx);
-    
+    boolean isClosed();
+
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/NameFormatter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/NameFormatter.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/NameFormatter.java	(revision 4100)
@@ -5,7 +5,7 @@
 
 public interface NameFormatter {
-    String format(Node node);
-    String format(Way way);
-    String format(Relation relation);
+    String format(INode node);
+    String format(IWay way);
+    String format(IRelation relation);
     String format(Changeset changeset);
 
Index: trunk/src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 4100)
@@ -5,4 +5,5 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 
@@ -138,4 +139,8 @@
 
     @Override public void visit(Visitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override public void visit(PrimitiveVisitor visitor) {
         visitor.visit(this);
     }
Index: trunk/src/org/openstreetmap/josm/data/osm/NodeData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 4100)
@@ -5,4 +5,5 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 
 public class NodeData extends PrimitiveData implements INode {
@@ -53,3 +54,14 @@
         return OsmPrimitiveType.NODE;
     }
+    
+    @Override 
+    public void visit(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public String getDisplayName(NameFormatter formatter) {
+        return formatter.format(this);
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4100)
@@ -14,5 +14,4 @@
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -1013,47 +1012,4 @@
 
     /**
-     * Replies the name of this primitive. The default implementation replies the value
-     * of the tag <tt>name</tt> or null, if this tag is not present.
-     *
-     * @return the name of this primitive
-     */
-    public String getName() {
-        return get("name");
-    }
-
-    /**
-     * Replies the a localized name for this primitive given by the value of the tags (in this order)
-     * <ul>
-     *   <li>name:lang_COUNTRY_Variant  of the current locale</li>
-     *   <li>name:lang_COUNTRY of the current locale</li>
-     *   <li>name:lang of the current locale</li>
-     *   <li>name of the current locale</li>
-     * </ul>
-     *
-     * null, if no such tag exists
-     *
-     * @return the name of this primitive
-     */
-    public String getLocalName() {
-        String key = "name:" + Locale.getDefault().toString();
-        if (get(key) != null)
-            return get(key);
-        key = "name:" + Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
-        if (get(key) != null)
-            return get(key);
-        key = "name:" + Locale.getDefault().getLanguage();
-        if (get(key) != null)
-            return get(key);
-        return getName();
-    }
-
-    /**
-     * Replies the display name of a primitive formatted by <code>formatter</code>
-     *
-     * @return the display name
-     */
-    public abstract String getDisplayName(NameFormatter formatter);
-
-    /**
      * Loads (clone) this primitive from provided PrimitiveData
      * @param data
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 4100)
@@ -45,24 +45,9 @@
     }
 
-    public static OsmPrimitiveType from(OsmPrimitive obj) {
-        return from(obj.getClass());
-    }
-
-    public static OsmPrimitiveType from(Class<? extends OsmPrimitive> cls) {
-        if (cls.equals(Node.class)) return NODE;
-        if (cls.equals(Way.class)) return WAY;
-        if (cls.equals(Relation.class)) return RELATION;
-        throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' is not an acceptable class. Got ''{1}''.", "cls", cls.toString()));
-    }
-
-    public static OsmPrimitiveType fromData(Class<? extends PrimitiveData> cls) {
-        if (cls.equals(NodeData.class)) return NODE;
-        if (cls.equals(WayData.class)) return WAY;
-        if (cls.equals(RelationData.class)) return RELATION;
-        throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' is not an acceptable class. Got ''{1}''.", "cls", cls.toString()));
-    }
-
-    public static OsmPrimitiveType fromData(PrimitiveData data) {
-        return fromData(data.getClass());
+    public static OsmPrimitiveType from(IPrimitive obj) {
+        if (obj instanceof INode) return NODE;
+        if (obj instanceof IWay) return WAY;
+        if (obj instanceof IRelation) return RELATION;
+        throw new IllegalArgumentException();
     }
 
Index: trunk/src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 4100)
@@ -10,4 +10,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.tools.CopyList;
@@ -162,4 +163,8 @@
 
     @Override public void visit(Visitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override public void visit(PrimitiveVisitor visitor) {
         visitor.visit(this);
     }
Index: trunk/src/org/openstreetmap/josm/data/osm/RelationData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 4100)
@@ -4,4 +4,6 @@
 import java.util.ArrayList;
 import java.util.List;
+
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 
 public class RelationData extends PrimitiveData implements IRelation {
@@ -60,3 +62,14 @@
         return OsmPrimitiveType.RELATION;
     }
+    
+    @Override 
+    public void visit(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public String getDisplayName(NameFormatter formatter) {
+        return formatter.format(this);
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 4100)
@@ -10,4 +10,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.tools.CopyList;
@@ -160,4 +161,8 @@
         visitor.visit(this);
     }
+    
+    @Override public void visit(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
 
     protected Way(long id, boolean allowNegative) {
@@ -409,4 +414,5 @@
     }
 
+    @Override
     public boolean isClosed() {
         if (isIncomplete()) return false;
Index: trunk/src/org/openstreetmap/josm/data/osm/WayData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 4100)
@@ -4,4 +4,5 @@
 import java.util.ArrayList;
 import java.util.List;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 
 public class WayData extends PrimitiveData implements IWay {
@@ -32,4 +33,10 @@
     }
 
+    @Override
+    public boolean isClosed() {
+        if (isIncomplete()) return false;
+        return nodes.get(0).equals(nodes.get(nodes.size() - 1));
+    }
+
     public void setNodes(List<Long> nodes) {
         this.nodes = new ArrayList<Long>(nodes);
@@ -50,3 +57,14 @@
         return OsmPrimitiveType.WAY;
     }
+    
+    @Override 
+    public void visit(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public String getDisplayName(NameFormatter formatter) {
+        return formatter.format(this);
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/PrimitiveVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/PrimitiveVisitor.java	(revision 4100)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/PrimitiveVisitor.java	(revision 4100)
@@ -0,0 +1,11 @@
+package org.openstreetmap.josm.data.osm.visitor;
+
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IWay;
+
+public interface PrimitiveVisitor {
+    void visit(INode n);
+    void visit(IWay w);
+    void visit(IRelation e);
+}
Index: trunk/src/org/openstreetmap/josm/gui/DefaultNameFormatter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/DefaultNameFormatter.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/gui/DefaultNameFormatter.java	(revision 4100)
@@ -17,4 +17,8 @@
 import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.NameFormatter;
 import org.openstreetmap.josm.data.osm.Node;
@@ -83,5 +87,5 @@
      * @return the decorated name
      */
-    protected String decorateNameWithId(String name, OsmPrimitive primitive) {
+    protected String decorateNameWithId(String name, IPrimitive primitive) {
         if (Main.pref.getBoolean("osm-primitives.showid"))
             if (Main.pref.getBoolean("osm-primitives.showid.new-primitives"))
@@ -99,5 +103,5 @@
      * @return the name
      */
-    public String format(Node node) {
+    public String format(INode node) {
         String name = "";
         if (node.isIncomplete()) {
@@ -157,5 +161,5 @@
      * @return the name
      */
-    public String format(Way way) {
+    public String format(IWay way) {
         String name = "";
         if (way.isIncomplete()) {
@@ -233,5 +237,5 @@
      * @return the name
      */
-    public String format(Relation relation) {
+    public String format(IRelation relation) {
         String name;
         if (relation.isIncomplete()) {
@@ -250,6 +254,8 @@
             name += trn("{0} member", "{0} members", mbno, mbno);
 
-            if (relationHasIncompleteMember(relation)) {
-                name += ", "+tr("incomplete");
+            if (relation instanceof Relation) {
+                if (relationHasIncompleteMember((Relation) relation)) {
+                    name += ", "+tr("incomplete");
+                }
             }
 
@@ -325,5 +331,5 @@
     }
 
-    private String getRelationTypeName(Relation relation) {
+    private String getRelationTypeName(IRelation relation) {
         String name = trc("Relation type", relation.get("type"));
         if (name == null) {
@@ -353,5 +359,5 @@
     }
 
-    private String getNameTagValue(Relation relation, String nameTag) {
+    private String getNameTagValue(IRelation relation, String nameTag) {
         if (nameTag.equals("name")) {
             if (Main.pref.getBoolean("osm-primitives.localize-name", true))
@@ -369,5 +375,5 @@
     }
 
-    private String getRelationName(Relation relation) {
+    private String getRelationName(IRelation relation) {
         String nameTag = null;
         for (String n : getNamingtagsForRelations()) {
@@ -403,5 +409,5 @@
      * @return the tooltip text
      */
-    public String buildDefaultToolTip(OsmPrimitive primitive) {
+    public String buildDefaultToolTip(IPrimitive primitive) {
         StringBuilder sb = new StringBuilder();
         sb.append("<html>");
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java	(revision 4100)
@@ -93,5 +93,5 @@
             //
             System.out.println(tr("Warning: object ''{0}'' is already deleted on the server. Skipping this object and retrying to upload.", p.getDisplayName(DefaultNameFormatter.getInstance())));
-            processedPrimitives.addAll(writer.getProcessedPrimitives());
+            processedPrimitives.addAll((Collection) writer.getProcessedPrimitives());
             processedPrimitives.add(p);
             toUpload.removeAll(processedPrimitives);
@@ -124,5 +124,5 @@
                     if (isCancelled()) return;
                     writer.uploadOsm(strategy, toUpload, changeset, m);
-                    processedPrimitives.addAll(writer.getProcessedPrimitives());
+                    processedPrimitives.addAll((Collection) writer.getProcessedPrimitives()); // OsmPrimitive in => OsmPrimitive out
                     break;
                 } catch(OsmApiPrimitiveGoneException e) {
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 4100)
@@ -9,4 +9,5 @@
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.logging.Logger;
@@ -194,5 +195,5 @@
             System.out.println(tr("Warning: object ''{0}'' is already deleted on the server. Skipping this object and retrying to upload.", p.getDisplayName(DefaultNameFormatter.getInstance())));
             monitor.appendLogMessage(tr("Object ''{0}'' is already deleted. Skipping object in upload.",p.getDisplayName(DefaultNameFormatter.getInstance())));
-            processedPrimitives.addAll(writer.getProcessedPrimitives());
+            processedPrimitives.addAll((Collection) writer.getProcessedPrimitives());
             processedPrimitives.add(p);
             toUpload.removeProcessed(processedPrimitives);
@@ -248,5 +249,5 @@
                     recoverFromGoneOnServer(e, getProgressMonitor());
                 } catch(ChangesetClosedException e) {
-                    processedPrimitives.addAll(writer.getProcessedPrimitives());
+                    processedPrimitives.addAll((Collection) writer.getProcessedPrimitives()); // OsmPrimitive in => OsmPrimitive out
                     changeset.setOpen(false);
                     switch(e.getSource()) {
@@ -273,5 +274,5 @@
                 } finally {
                     if (writer != null) {
-                        processedPrimitives.addAll(writer.getProcessedPrimitives());
+                        processedPrimitives.addAll((Collection) writer.getProcessedPrimitives());
                     }
                     synchronized(this) {
Index: trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 4100)
@@ -17,5 +17,5 @@
 
 import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.PrimitiveId;
@@ -46,9 +46,9 @@
      * is set
      */
-    private Set<OsmPrimitive> processed;
+    private Set<IPrimitive> processed;
     /**
      * the collection of primitives being uploaded
      */
-    private Collection<OsmPrimitive> primitives;
+    private Collection<? extends IPrimitive> primitives;
 
     /**
@@ -58,10 +58,10 @@
      * assumes an empty collection.
      */
-    public DiffResultProcessor(Collection<OsmPrimitive> primitives) {
+    public DiffResultProcessor(Collection<? extends IPrimitive> primitives) {
         if (primitives == null) {
             primitives = Collections.emptyList();
         }
         this.primitives = primitives;
-        this.processed = new HashSet<OsmPrimitive>();
+        this.processed = new HashSet<IPrimitive>();
     }
 
@@ -108,5 +108,5 @@
      * @return the collection of processed primitives
      */
-    protected Set<OsmPrimitive> postProcess(Changeset cs,ProgressMonitor monitor) {
+    protected Set<IPrimitive> postProcess(Changeset cs, ProgressMonitor monitor) {
         if (monitor == null) {
             monitor = NullProgressMonitor.INSTANCE;
@@ -116,5 +116,5 @@
             monitor.setTicksCount(primitives.size());
             monitor.setTicks(0);
-            for (OsmPrimitive p: primitives) {
+            for (IPrimitive p : primitives) {
                 monitor.worked(1);
                 DiffResultEntry entry = diffResults.get(p.getPrimitiveId());
Index: trunk/src/org/openstreetmap/josm/io/OsmApi.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmApi.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/io/OsmApi.java	(revision 4100)
@@ -30,5 +30,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -230,5 +230,5 @@
      * @return XML string
      */
-    private String toXml(OsmPrimitive o, boolean addBody) {
+    private String toXml(IPrimitive o, boolean addBody) {
         swriter.getBuffer().setLength(0);
         osmWriter.setWithBody(addBody);
@@ -250,5 +250,5 @@
         swriter.getBuffer().setLength(0);
         osmWriter.header();
-        s.visit(osmWriter);
+        osmWriter.visit(s);
         osmWriter.footer();
         osmWriter.out.flush();
@@ -280,5 +280,5 @@
      * @throws OsmTransferException if something goes wrong
      */
-    public void createPrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
+    public void createPrimitive(IPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
         String ret = "";
         try {
@@ -300,5 +300,5 @@
      * @throws OsmTransferException if something goes wrong
      */
-    public void modifyPrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
+    public void modifyPrimitive(IPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
         String ret = null;
         try {
@@ -320,5 +320,5 @@
      * @throws OsmTransferException if something goes wrong
      */
-    public void deletePrimitive(OsmPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
+    public void deletePrimitive(IPrimitive osm, ProgressMonitor monitor) throws OsmTransferException {
         ensureValidChangeset();
         initialize(monitor);
@@ -440,5 +440,5 @@
      * @throws OsmTransferException if something is wrong
      */
-    public Collection<OsmPrimitive> uploadDiff(Collection<OsmPrimitive> list, ProgressMonitor monitor) throws OsmTransferException {
+    public Collection<IPrimitive> uploadDiff(Collection<? extends IPrimitive> list, ProgressMonitor monitor) throws OsmTransferException {
         try {
             monitor.beginTask("", list.size() * 2);
Index: trunk/src/org/openstreetmap/josm/io/OsmChangeBuilder.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangeBuilder.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangeBuilder.java	(revision 4100)
@@ -9,5 +9,5 @@
 
 import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 
 /**
@@ -38,5 +38,5 @@
     }
 
-    protected void write(OsmPrimitive p) {
+    protected void write(IPrimitive p) {
         if (p.isDeleted()) {
             switchMode("delete");
@@ -81,16 +81,16 @@
 
     /**
-     * Appends a collection of {@see OsmPrimitive}s to the OsmChange document.
+     * Appends a collection of Primitives to the OsmChange document.
      *
      * @param primitives the collection of primitives. Ignored if null.
      * @throws IllegalStateException thrown if the prologs has not been written yet
      * @see #start()
-     * @see #append(OsmPrimitive)
+     * @see #append(IPrimitive)
      */
-    public void append(Collection<OsmPrimitive> primitives) throws IllegalStateException{
+    public void append(Collection<? extends IPrimitive> primitives) throws IllegalStateException{
         if (primitives == null) return;
         if (!prologWritten)
             throw new IllegalStateException(tr("Prolog of OsmChange document not written yet. Please write frst."));
-        for (OsmPrimitive p : primitives) {
+        for (IPrimitive p : primitives) {
             write(p);
         }
@@ -98,5 +98,5 @@
 
     /**
-     * Appends an {@see OsmPrimitive} to the OsmChange document.
+     * Appends an Primitive to the OsmChange document.
      *
      * @param p the primitive. Ignored if null.
@@ -106,5 +106,5 @@
 
      */
-    public void append(OsmPrimitive p) {
+    public void append(IPrimitive p) {
         if (p == null) return;
         if (!prologWritten)
Index: trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 4100)
@@ -14,5 +14,5 @@
 
 import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.gui.io.UploadStrategySpecification;
@@ -39,5 +39,5 @@
      * than where passed in the list to upload*.
      */
-    private Collection<OsmPrimitive> processed;
+    private Collection<IPrimitive> processed;
 
     private OsmApi api = OsmApi.getOsmApi();
@@ -76,10 +76,10 @@
      * @throws OsmTransferException thrown if an exception occurs
      */
-    protected void uploadChangesIndividually(Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
+    protected void uploadChangesIndividually(Collection<? extends IPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
         try {
             progressMonitor.beginTask(tr("Starting to upload with one request per primitive ..."));
             progressMonitor.setTicksCount(primitives.size());
             uploadStartTime = System.currentTimeMillis();
-            for (OsmPrimitive osm : primitives) {
+            for (IPrimitive osm : primitives) {
                 int progress = progressMonitor.getTicks();
                 String time_left_str = timeLeft(progress, primitives.size());
@@ -118,5 +118,5 @@
      * @throws OsmTransferException thrown if an exception occurs
      */
-    protected void uploadChangesAsDiffUpload(Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
+    protected void uploadChangesAsDiffUpload(Collection<? extends IPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
         try {
             progressMonitor.beginTask(tr("Starting to upload in one request ..."));
@@ -138,11 +138,11 @@
      * @throws OsmTransferException thrown if an exception occurs
      */
-    protected void uploadChangesInChunks(Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor, int chunkSize) throws OsmTransferException, IllegalArgumentException {
+    protected void uploadChangesInChunks(Collection<? extends IPrimitive> primitives, ProgressMonitor progressMonitor, int chunkSize) throws OsmTransferException, IllegalArgumentException {
         if (chunkSize <=0)
             throw new IllegalArgumentException(tr("Value >0 expected for parameter ''{0}'', got {1}", "chunkSize", chunkSize));
         try {
             progressMonitor.beginTask(tr("Starting to upload in chunks..."));
-            List<OsmPrimitive> chunk = new ArrayList<OsmPrimitive>(chunkSize);
-            Iterator<OsmPrimitive> it = primitives.iterator();
+            List<IPrimitive> chunk = new ArrayList<IPrimitive>(chunkSize);
+            Iterator<? extends IPrimitive> it = primitives.iterator();
             int numChunks = (int)Math.ceil((double)primitives.size() / (double)chunkSize);
             int i= 0;
@@ -181,7 +181,7 @@
      * @throws OsmTransferException thrown if something goes wrong
      */
-    public void uploadOsm(UploadStrategySpecification strategy, Collection<OsmPrimitive> primitives, Changeset changeset, ProgressMonitor monitor) throws OsmTransferException {
+    public void uploadOsm(UploadStrategySpecification strategy, Collection<? extends IPrimitive> primitives, Changeset changeset, ProgressMonitor monitor) throws OsmTransferException {
         CheckParameterUtil.ensureParameterNotNull(changeset, "changeset");
-        processed = new LinkedList<OsmPrimitive>();
+        processed = new LinkedList<IPrimitive>();
         monitor = monitor == null ? NullProgressMonitor.INSTANCE : monitor;
         monitor.beginTask(tr("Uploading data ..."));
@@ -214,5 +214,5 @@
     }
 
-    void makeApiRequest(OsmPrimitive osm, ProgressMonitor progressMonitor) throws OsmTransferException {
+    void makeApiRequest(IPrimitive osm, ProgressMonitor progressMonitor) throws OsmTransferException {
         if (osm.isDeleted()) {
             api.deletePrimitive(osm, progressMonitor);
@@ -236,5 +236,5 @@
      * @return the collection of successfully processed primitives
      */
-    public Collection<OsmPrimitive> getProcessedPrimitives() {
+    public Collection<IPrimitive> getProcessedPrimitives() {
         return processed;
     }
Index: trunk/src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 4100)
@@ -16,12 +16,14 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DataSource;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Tagged;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.tools.DateUtils;
 
@@ -31,5 +33,5 @@
  * @author imi
  */
-public class OsmWriter extends XmlWriter implements Visitor {
+public class OsmWriter extends XmlWriter implements PrimitiveVisitor {
 
     public static final String DEFAULT_API_VERSION = "0.6";
@@ -67,5 +69,5 @@
 
     private static final Comparator<OsmPrimitive> byIdComparator = new Comparator<OsmPrimitive>() {
-        public int compare(OsmPrimitive o1, OsmPrimitive o2) {
+        @Override public int compare(OsmPrimitive o1, OsmPrimitive o2) {
             return (o1.getUniqueId()<o2.getUniqueId() ? -1 : (o1.getUniqueId()==o2.getUniqueId() ? 0 : 1));
         }
@@ -112,5 +114,6 @@
     }
 
-    public void visit(Node n) {
+    @Override
+    public void visit(INode n) {
         if (n.isIncomplete()) return;
         addCommon(n, "node");
@@ -123,5 +126,6 @@
     }
 
-    public void visit(Way w) {
+    @Override
+    public void visit(IWay w) {
         if (w.isIncomplete()) return;
         addCommon(w, "way");
@@ -130,6 +134,6 @@
         } else {
             out.println(">");
-            for (Node n : w.getNodes()) {
-                out.println("    <nd ref='"+n.getUniqueId()+"' />");
+            for (int i=0; i<w.getNodesCount(); ++i) {
+                out.println("    <nd ref='"+w.getNodeId(i) +"' />");
             }
             addTags(w, "way", false);
@@ -137,5 +141,6 @@
     }
 
-    public void visit(Relation e) {
+    @Override
+    public void visit(IRelation e) {
         if (e.isIncomplete()) return;
         addCommon(e, "relation");
@@ -144,9 +149,9 @@
         } else {
             out.println(">");
-            for (RelationMember em : e.getMembers()) {
+            for (int i=0; i<e.getMembersCount(); ++i) {
                 out.print("    <member type='");
-                out.print(OsmPrimitiveType.from(em.getMember()).getAPIName());
-                out.println("' ref='"+em.getMember().getUniqueId()+"' role='" +
-                        XmlWriter.encode(em.getRole()) + "' />");
+                out.print(e.getMemberType(i));
+                out.println("' ref='"+e.getMemberId(i)+"' role='" +
+                        XmlWriter.encode(e.getRole(i)) + "' />");
             }
             addTags(e, "relation", false);
@@ -181,5 +186,5 @@
 
     private static final Comparator<Entry<String, String>> byKeyComparator = new Comparator<Entry<String,String>>() {
-        public int compare(Entry<String, String> o1, Entry<String, String> o2) {
+        @Override public int compare(Entry<String, String> o1, Entry<String, String> o2) {
             return o1.getKey().compareTo(o2.getKey());
         }
@@ -211,5 +216,5 @@
      * id, action, user, and visible.
      */
-    private void addCommon(OsmPrimitive osm, String tagname) {
+    private void addCommon(IPrimitive osm, String tagname) {
         out.print("  <"+tagname);
         if (osm.getUniqueId() != 0) {
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4099)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4100)
@@ -47,4 +47,17 @@
         }
         return null;
+    }
+    
+    /**
+     * Filter a collection by (sub)class.
+     * This is an efficient read-only implementation.
+     */
+    public static <S, T extends S> SubclassFilteredCollection<S, T> filteredCollection(Collection<S> collection, final Class<T> klass) {
+        return new SubclassFilteredCollection<S, T>(collection, new Predicate<S>() {
+            @Override
+            public boolean evaluate(S o) {
+                return klass.isInstance(o);
+            }
+        });
     }
 
