Index: trunk/src/org/openstreetmap/josm/data/osm/INode.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/INode.java	(revision 4098)
+++ trunk/src/org/openstreetmap/josm/data/osm/INode.java	(revision 4098)
@@ -0,0 +1,14 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+public interface INode extends IPrimitive {
+    
+    LatLon getCoor();
+    void setCoor(LatLon coor);
+    EastNorth getEastNorth();
+    void setEastNorth(EastNorth eastNorth);
+
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 4098)
+++ trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 4098)
@@ -0,0 +1,29 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Date;
+
+/**
+ * IPrimitive captures the common functions of OsmPrimitive and PrimitiveData.
+ */
+public interface IPrimitive extends Tagged, PrimitiveId {
+
+    boolean isModified();
+    void setModified(boolean modified);
+    boolean isVisible();
+    void setVisible(boolean visible);
+    boolean isDeleted();
+    void setDeleted(boolean deleted);
+    boolean isIncomplete();
+    long getId();
+    int getVersion();
+    void setOsmId(long id, int version);
+    User getUser();
+    void setUser(User user);
+    Date getTimestamp();
+    void setTimestamp(Date timestamp);
+    boolean isTimestampEmpty();
+    int getChangesetId();
+    void setChangesetId(int changesetId);
+
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/IRelation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/IRelation.java	(revision 4098)
+++ trunk/src/org/openstreetmap/josm/data/osm/IRelation.java	(revision 4098)
@@ -0,0 +1,11 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+public interface IRelation extends IPrimitive {
+
+    int getMembersCount();
+    long getMemberId(int idx);
+    String getRole(int idx);
+    OsmPrimitiveType getMemberType(int idx);
+
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/IWay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/IWay.java	(revision 4098)
+++ trunk/src/org/openstreetmap/josm/data/osm/IWay.java	(revision 4098)
@@ -0,0 +1,9 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+public interface IWay extends IPrimitive {
+
+    int getNodesCount();
+    long getNodeId(int idx);
+    
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 4098)
@@ -12,8 +12,9 @@
  * @author imi
  */
-public final class Node extends OsmPrimitive {
+public final class Node extends OsmPrimitive implements INode {
 
     private CachedLatLon coor;
 
+    @Override
     public final void setCoor(LatLon coor) {
         if(coor != null){
@@ -22,4 +23,5 @@
     }
 
+    @Override
     public final void setEastNorth(EastNorth eastNorth) {
         if(eastNorth != null) {
@@ -41,8 +43,10 @@
     }
 
+    @Override
     public final LatLon getCoor() {
         return coor;
     }
 
+    @Override
     public final EastNorth getEastNorth() {
         return coor != null ? coor.getEastNorth() : null;
@@ -210,4 +214,5 @@
     }
 
+    @Override
     public int compareTo(OsmPrimitive o) {
         return o instanceof Node ? Long.valueOf(getUniqueId()).compareTo(o.getUniqueId()) : 1;
@@ -219,4 +224,5 @@
     }
 
+    @Override
     public OsmPrimitiveType getType() {
         return OsmPrimitiveType.NODE;
Index: trunk/src/org/openstreetmap/josm/data/osm/NodeData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 4098)
@@ -6,5 +6,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 
-public class NodeData extends PrimitiveData {
+public class NodeData extends PrimitiveData implements INode {
 
     private final CachedLatLon coor = new CachedLatLon(0, 0);
@@ -28,16 +28,20 @@
     }
 
+    @Override
     public LatLon getCoor() {
         return coor;
     }
 
+    @Override
     public void setCoor(LatLon coor) {
         this.coor.setCoor(coor);
     }
 
+    @Override
     public EastNorth getEastNorth() {
         return this.coor.getEastNorth();
     }
 
+    @Override
     public void setEastNorth(EastNorth eastNorth) {
         this.coor.setEastNorth(eastNorth);
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4098)
@@ -40,5 +40,5 @@
  * @author imi
  */
-abstract public class OsmPrimitive implements Comparable<OsmPrimitive>, Tagged, PrimitiveId {
+abstract public class OsmPrimitive implements Comparable<OsmPrimitive>, IPrimitive {
 
     private static final AtomicLong idCounter = new AtomicLong(0);
@@ -188,5 +188,5 @@
      */
     public static final Predicate<OsmPrimitive> isUsablePredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.isUsable();
         }
@@ -194,5 +194,5 @@
 
     public static final Predicate<OsmPrimitive> isSelectablePredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.isSelectable();
         }
@@ -200,5 +200,5 @@
 
     public static final Predicate<OsmPrimitive> nonDeletedPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return !primitive.isDeleted();
         }
@@ -206,5 +206,5 @@
 
     public static final Predicate<OsmPrimitive> nonDeletedCompletePredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return !primitive.isDeleted() && !primitive.isIncomplete();
         }
@@ -212,5 +212,5 @@
 
     public static final Predicate<OsmPrimitive> nonDeletedPhysicalPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation);
         }
@@ -218,5 +218,5 @@
 
     public static final Predicate<OsmPrimitive> modifiedPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.isModified();
         }
@@ -224,5 +224,5 @@
 
     public static final Predicate<OsmPrimitive> nodePredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.getClass() == Node.class;
         }
@@ -230,5 +230,5 @@
 
     public static final Predicate<OsmPrimitive> wayPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.getClass() == Way.class;
         }
@@ -236,5 +236,5 @@
 
     public static final Predicate<OsmPrimitive> relationPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return primitive.getClass() == Relation.class;
         }
@@ -242,5 +242,5 @@
 
     public static final Predicate<OsmPrimitive> allPredicate = new Predicate<OsmPrimitive>() {
-        public boolean evaluate(OsmPrimitive primitive) {
+        @Override public boolean evaluate(OsmPrimitive primitive) {
             return true;
         }
@@ -397,5 +397,6 @@
      * @see #setVersion(int)
      */
-    public long getVersion() {
+    @Override
+    public int getVersion() {
         return version;
     }
@@ -406,4 +407,5 @@
      * @return the id of this primitive.
      */
+    @Override
     public long getId() {
         long id = this.id;
@@ -415,4 +417,5 @@
      * @return Osm id if primitive already exists on the server. Unique negative value if primitive is new
      */
+    @Override
     public long getUniqueId() {
         return id;
@@ -423,4 +426,5 @@
      * @return True if primitive is new (not yet uploaded the server, id <= 0)
      */
+    @Override
     public boolean isNew() {
         return id <= 0;
@@ -449,4 +453,5 @@
      * @throws DataIntegrityProblemException If id is changed and primitive was already added to the dataset
      */
+    @Override
     public void setOsmId(long id, int version) {
         boolean locked = writeLock();
@@ -496,4 +501,5 @@
      * @return the user who has last touched this object. May be null.
      */
+    @Override
     public User getUser() {
         return user;
@@ -505,4 +511,5 @@
      * @param user the user
      */
+    @Override
     public void setUser(User user) {
         boolean locked = writeLock();
@@ -521,4 +528,5 @@
      * @return the id of the changeset this primitive was last uploaded to.
      */
+    @Override
     public int getChangesetId() {
         return changesetId;
@@ -533,4 +541,5 @@
      * @throws IllegalArgumentException thrown if id < 0
      */
+    @Override
     public void setChangesetId(int changesetId) throws IllegalStateException, IllegalArgumentException {
         boolean locked = writeLock();
@@ -566,4 +575,5 @@
     }
 
+    @Override
     public void setTimestamp(Date timestamp) {
         boolean locked = writeLock();
@@ -581,8 +591,10 @@
      *
      */
+    @Override
     public Date getTimestamp() {
         return new Date(timestamp * 1000l);
     }
 
+    @Override
     public boolean isTimestampEmpty() {
         return timestamp == 0;
@@ -674,4 +686,5 @@
      * @param modified true, if this primitive is to be modified
      */
+    @Override
     public void setModified(boolean modified) {
         updateFlags(FLAG_MODIFIED, modified);
@@ -688,4 +701,5 @@
      * the server
      */
+    @Override
     public boolean isModified() {
         return (flags & FLAG_MODIFIED) != 0;
@@ -698,4 +712,5 @@
      * @see #setDeleted(boolean)
      */
+    @Override
     public boolean isDeleted() {
         return (flags & FLAG_DELETED) != 0;
@@ -737,4 +752,5 @@
      * @see #setVisible(boolean)
      */
+    @Override
     public boolean isVisible() {
         return (flags & FLAG_VISIBLE) != 0;
@@ -749,4 +765,5 @@
      * id==0
      */
+    @Override
     public void setVisible(boolean visible) throws IllegalStateException{
         boolean locked = writeLock();
@@ -767,4 +784,5 @@
      * @param deleted  true, if this primitive is deleted; false, otherwise
      */
+    @Override
     public void setDeleted(boolean deleted) {
         boolean locked = writeLock();
@@ -805,4 +823,5 @@
     }
 
+    @Override
     public boolean isIncomplete() {
         return (flags & FLAG_INCOMPLETE) != 0;
@@ -995,4 +1014,5 @@
      * back to the primitive, use setKeys() to modify the keys
      */
+    @Override
     public Map<String, String> getKeys() {
         Map<String, String> result = new HashMap<String, String>();
@@ -1012,4 +1032,5 @@
      * @param keys the key/value pairs to set. If null, removes all existing key/value pairs.
      */
+    @Override
     public void setKeys(Map<String, String> keys) {
         boolean locked = writeLock();
@@ -1043,4 +1064,5 @@
      * @see #remove(String)
      */
+    @Override
     public final void put(String key, String value) {
         boolean locked = writeLock();
@@ -1081,4 +1103,5 @@
      * @param key  the key to be removed. Ignored, if key is null.
      */
+    @Override
     public final void remove(String key) {
         boolean locked = writeLock();
@@ -1113,4 +1136,5 @@
      * @since 1843
      */
+    @Override
     public final void removeAll() {
         boolean locked = writeLock();
@@ -1133,4 +1157,5 @@
      * @return the value for key <code>key</code>.
      */
+    @Override
     public final String get(String key) {
         String[] keys = this.keys;
@@ -1145,4 +1170,5 @@
     }
 
+    @Override
     public final Collection<String> keySet() {
         String[] keys = this.keys;
@@ -1162,4 +1188,5 @@
      *   otherwise
      */
+    @Override
     public final boolean hasKeys() {
         return keys != null;
Index: trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 4098)
@@ -1,4 +1,6 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.util.ArrayList;
@@ -16,5 +18,5 @@
  *
  */
-public abstract class PrimitiveData implements Tagged, PrimitiveId {
+public abstract class PrimitiveData implements IPrimitive {
 
     // Useful?
@@ -51,22 +53,29 @@
     private int changesetId;
 
+    @Override
     public boolean isModified() {
         return modified;
     }
+    @Override
     public void setModified(boolean modified) {
         this.modified = modified;
     }
+    @Override
     public boolean isVisible() {
         return visible;
     }
+    @Override
     public void setVisible(boolean visible) {
         this.visible = visible;
     }
+    @Override
     public boolean isDeleted() {
         return deleted;
     }
+    @Override
     public void setDeleted(boolean deleted) {
         this.deleted = deleted;
     }
+    @Override
     public long getId() {
         return id > 0 ? id : 0;
@@ -75,10 +84,13 @@
         this.id = id;
     }
+    @Override
     public User getUser() {
         return user;
     }
+    @Override
     public void setUser(User user) {
         this.user = user;
     }
+    @Override
     public int getVersion() {
         return version;
@@ -87,22 +99,42 @@
         this.version = version;
     }
+    @Override
+    public void setOsmId(long id, int version) {
+        if (id <= 0)
+            throw new IllegalArgumentException(tr("ID > 0 expected. Got {0}.", id));
+        if (version <= 0)
+            throw new IllegalArgumentException(tr("Version > 0 expected. Got {0}.", version));
+        this.id = id;
+        this.version = version;
+        this.setIncomplete(false);
+    }
+    @Override
     public Date getTimestamp() {
         return timestamp;
     }
+    @Override
     public void setTimestamp(Date timestamp) {
         this.timestamp = timestamp;
     }
-
+    @Override
+    public boolean isTimestampEmpty() {
+        return timestamp == null || timestamp.getTime() == 0;
+    }
+
+    @Override
     public int getChangesetId() {
         return changesetId;
     }
 
+    @Override
     public void setChangesetId(int changesetId) {
         this.changesetId = changesetId;
     }
 
+    @Override
     public Map<String, String> getKeys() {
         return keys;
     }
+    @Override
     public boolean isIncomplete() {
         return incomplete;
@@ -141,28 +173,35 @@
     // Tagged implementation
 
+    @Override
     public String get(String key) {
         return keys.get(key);
     }
 
+    @Override
     public boolean hasKeys() {
         return !keys.isEmpty();
     }
 
+    @Override
     public Collection<String> keySet() {
         return keys.keySet();
     }
 
+    @Override
     public void put(String key, String value) {
         keys.put(key, value);
     }
 
+    @Override
     public void remove(String key) {
         keys.remove(key);
     }
 
+    @Override
     public void removeAll() {
         keys.clear();
     }
 
+    @Override
     public void setKeys(Map<String, String> keys) {
         this.keys.clear();
@@ -191,4 +230,5 @@
      * PrimitiveId implementation. Returns the same value as getId()
      */
+    @Override
     public long getUniqueId() {
         return id;
@@ -204,8 +244,10 @@
     }
 
+    @Override
     public boolean isNew() {
         return id <= 0;
     }
 
+    @Override
     public abstract OsmPrimitiveType getType();
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 4098)
@@ -18,5 +18,5 @@
  * @author Frederik Ramm <frederik@remote.org>
  */
-public final class Relation extends OsmPrimitive {
+public final class Relation extends OsmPrimitive implements IRelation {
 
     private RelationMember[] members = new RelationMember[0];
@@ -65,4 +65,5 @@
      * @return number of members
      */
+    @Override
     public int getMembersCount() {
         return members.length;
@@ -143,4 +144,19 @@
             writeUnlock(locked);
         }
+    }
+
+    @Override
+    public long getMemberId(int idx) {
+        return members[idx].getUniqueId();
+    }
+
+    @Override
+    public String getRole(int idx) {
+        return members[idx].getRole();
+    }
+
+    @Override
+    public OsmPrimitiveType getMemberType(int idx) {
+        return members[idx].getType();
     }
 
@@ -266,4 +282,5 @@
     }
 
+    @Override
     public int compareTo(OsmPrimitive o) {
         return o instanceof Relation ? Long.valueOf(getUniqueId()).compareTo(o.getUniqueId()) : -1;
@@ -373,8 +390,10 @@
     }
 
+    @Override
     public OsmPrimitiveType getType() {
         return OsmPrimitiveType.RELATION;
     }
 
+    @Override
     public OsmPrimitiveType getDisplayType() {
         return isMultipolygon() ? OsmPrimitiveType.MULTIPOLYGON
Index: trunk/src/org/openstreetmap/josm/data/osm/RelationData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 4098)
@@ -5,5 +5,5 @@
 import java.util.List;
 
-public class RelationData extends PrimitiveData {
+public class RelationData extends PrimitiveData implements IRelation {
 
     private List<RelationMemberData> members = new ArrayList<RelationMemberData>();
@@ -27,4 +27,24 @@
 
     @Override
+    public int getMembersCount() {
+        return members.size();
+    }
+
+    @Override
+    public long getMemberId(int idx) {
+        return members.get(idx).getMemberId();
+    }
+
+    @Override
+    public String getRole(int idx) {
+        return members.get(idx).getRole();
+    }
+
+    @Override
+    public OsmPrimitiveType getMemberType(int idx) {
+        return members.get(idx).getMemberType();
+    }
+
+    @Override
     public RelationData makeCopy() {
         return new RelationData(this);
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 4098)
@@ -19,5 +19,5 @@
  * @author imi
  */
-public final class Way extends OsmPrimitive {
+public final class Way extends OsmPrimitive implements IWay {
 
     /**
@@ -94,4 +94,5 @@
      * @since 1862
      */
+    @Override
     public int getNodesCount() {
         return nodes.length;
@@ -109,4 +110,9 @@
     public Node getNode(int index) {
         return nodes[index];
+    }
+
+    @Override
+    public long getNodeId(int idx) {
+        return nodes[idx].getUniqueId();
     }
 
@@ -275,4 +281,5 @@
     }
 
+    @Override
     public int compareTo(OsmPrimitive o) {
         if (o instanceof Relation)
@@ -444,4 +451,5 @@
     }
 
+    @Override
     public OsmPrimitiveType getType() {
         return OsmPrimitiveType.WAY;
Index: trunk/src/org/openstreetmap/josm/data/osm/WayData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 4097)
+++ trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 4098)
@@ -5,5 +5,5 @@
 import java.util.List;
 
-public class WayData extends PrimitiveData {
+public class WayData extends PrimitiveData implements IWay {
 
     private List<Long> nodes = new ArrayList<Long>();
@@ -20,4 +20,14 @@
     public List<Long> getNodes() {
         return nodes;
+    }
+
+    @Override
+    public int getNodesCount() {
+        return nodes.size();
+    }
+
+    @Override
+    public long getNodeId(int idx) {
+        return nodes.get(idx);
     }
 
