001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm; 003 004import java.util.HashMap; 005import java.util.Iterator; 006import java.util.Map; 007import java.util.Map.Entry; 008import java.util.Set; 009import java.util.stream.Collectors; 010 011import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive; 012import org.openstreetmap.josm.tools.CheckParameterUtil; 013 014/** 015 * A ChangesetDataSet holds the content of a changeset. 016 */ 017public class ChangesetDataSet { 018 019 /** 020 * Type of primitive modification. 021 */ 022 public enum ChangesetModificationType { 023 /** The primitive has been created */ 024 CREATED, 025 /** The primitive has been updated */ 026 UPDATED, 027 /** The primitive has been deleted */ 028 DELETED 029 } 030 031 /** 032 * An entry in the changeset dataset. 033 */ 034 public interface ChangesetDataSetEntry { 035 036 /** 037 * Returns the type of modification. 038 * @return the type of modification 039 */ 040 ChangesetModificationType getModificationType(); 041 042 /** 043 * Returns the affected history primitive. 044 * @return the affected history primitive 045 */ 046 HistoryOsmPrimitive getPrimitive(); 047 } 048 049 private final Map<PrimitiveId, HistoryOsmPrimitive> primitives = new HashMap<>(); 050 private final Map<PrimitiveId, ChangesetModificationType> modificationTypes = new HashMap<>(); 051 052 /** 053 * Remembers a history primitive with the given modification type 054 * 055 * @param primitive the primitive. Must not be null. 056 * @param cmt the modification type. Must not be null. 057 * @throws IllegalArgumentException if primitive is null 058 * @throws IllegalArgumentException if cmt is null 059 */ 060 public void put(HistoryOsmPrimitive primitive, ChangesetModificationType cmt) { 061 CheckParameterUtil.ensureParameterNotNull(primitive, "primitive"); 062 CheckParameterUtil.ensureParameterNotNull(cmt, "cmt"); 063 primitives.put(primitive.getPrimitiveId(), primitive); 064 modificationTypes.put(primitive.getPrimitiveId(), cmt); 065 } 066 067 /** 068 * Replies true if the changeset content contains the object with primitive <code>id</code>. 069 * @param id the id. 070 * @return true if the changeset content contains the object with primitive <code>id</code> 071 */ 072 public boolean contains(PrimitiveId id) { 073 if (id == null) return false; 074 return primitives.containsKey(id); 075 } 076 077 /** 078 * Replies the modification type for the object with id <code>id</code>. Replies null, if id is null or 079 * if the object with id <code>id</code> isn't in the changeset content. 080 * 081 * @param id the id 082 * @return the modification type 083 */ 084 public ChangesetModificationType getModificationType(PrimitiveId id) { 085 if (!contains(id)) return null; 086 return modificationTypes.get(id); 087 } 088 089 /** 090 * Replies true if the primitive with id <code>id</code> was created in this 091 * changeset. Replies false, if id is null. 092 * 093 * @param id the id 094 * @return true if the primitive with id <code>id</code> was created in this 095 * changeset. 096 */ 097 public boolean isCreated(PrimitiveId id) { 098 if (!contains(id)) return false; 099 return ChangesetModificationType.CREATED.equals(getModificationType(id)); 100 } 101 102 /** 103 * Replies true if the primitive with id <code>id</code> was updated in this 104 * changeset. Replies false, if id is null. 105 * 106 * @param id the id 107 * @return true if the primitive with id <code>id</code> was updated in this 108 * changeset. 109 */ 110 public boolean isUpdated(PrimitiveId id) { 111 if (!contains(id)) return false; 112 return ChangesetModificationType.UPDATED.equals(getModificationType(id)); 113 } 114 115 /** 116 * Replies true if the primitive with id <code>id</code> was deleted in this 117 * changeset. Replies false, if id is null. 118 * 119 * @param id the id 120 * @return true if the primitive with id <code>id</code> was deleted in this 121 * changeset. 122 */ 123 public boolean isDeleted(PrimitiveId id) { 124 if (!contains(id)) return false; 125 return ChangesetModificationType.DELETED.equals(getModificationType(id)); 126 } 127 128 /** 129 * Replies the set of primitives with a specific modification type 130 * 131 * @param cmt the modification type. Must not be null. 132 * @return the set of primitives 133 * @throws IllegalArgumentException if cmt is null 134 */ 135 public Set<HistoryOsmPrimitive> getPrimitivesByModificationType(ChangesetModificationType cmt) { 136 CheckParameterUtil.ensureParameterNotNull(cmt, "cmt"); 137 return modificationTypes.entrySet().stream() 138 .filter(entry -> entry.getValue().equals(cmt)) 139 .map(entry -> primitives.get(entry.getKey())) 140 .collect(Collectors.toSet()); 141 } 142 143 /** 144 * Replies the number of objects in the dataset 145 * 146 * @return the number of objects in the dataset 147 */ 148 public int size() { 149 return primitives.size(); 150 } 151 152 /** 153 * Replies the {@link HistoryOsmPrimitive} with id <code>id</code> from this dataset. 154 * null, if there is no such primitive in the data set. 155 * 156 * @param id the id 157 * @return the {@link HistoryOsmPrimitive} with id <code>id</code> from this dataset 158 */ 159 public HistoryOsmPrimitive getPrimitive(PrimitiveId id) { 160 if (id == null) return null; 161 return primitives.get(id); 162 } 163 164 /** 165 * Returns an iterator over dataset entries. 166 * @return an iterator over dataset entries 167 */ 168 public Iterator<ChangesetDataSetEntry> iterator() { 169 return new DefaultIterator(); 170 } 171 172 private static class DefaultChangesetDataSetEntry implements ChangesetDataSetEntry { 173 private final ChangesetModificationType modificationType; 174 private final HistoryOsmPrimitive primitive; 175 176 DefaultChangesetDataSetEntry(ChangesetModificationType modificationType, HistoryOsmPrimitive primitive) { 177 this.modificationType = modificationType; 178 this.primitive = primitive; 179 } 180 181 @Override 182 public ChangesetModificationType getModificationType() { 183 return modificationType; 184 } 185 186 @Override 187 public HistoryOsmPrimitive getPrimitive() { 188 return primitive; 189 } 190 } 191 192 private class DefaultIterator implements Iterator<ChangesetDataSetEntry> { 193 private final Iterator<Entry<PrimitiveId, ChangesetModificationType>> typeIterator; 194 195 DefaultIterator() { 196 typeIterator = modificationTypes.entrySet().iterator(); 197 } 198 199 @Override 200 public boolean hasNext() { 201 return typeIterator.hasNext(); 202 } 203 204 @Override 205 public ChangesetDataSetEntry next() { 206 Entry<PrimitiveId, ChangesetModificationType> next = typeIterator.next(); 207 return new DefaultChangesetDataSetEntry(next.getValue(), primitives.get(next.getKey())); 208 } 209 210 @Override 211 public void remove() { 212 throw new UnsupportedOperationException(); 213 } 214 } 215}