001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.vector; 003 004import java.util.Collection; 005import java.util.Collections; 006import java.util.HashSet; 007import java.util.LinkedList; 008import java.util.Map; 009import java.util.Set; 010import java.util.concurrent.locks.ReentrantReadWriteLock; 011 012import org.openstreetmap.gui.jmapviewer.Tile; 013import org.openstreetmap.josm.data.DataSource; 014import org.openstreetmap.josm.data.osm.DataSet; 015import org.openstreetmap.josm.data.osm.INode; 016import org.openstreetmap.josm.data.osm.IPrimitive; 017import org.openstreetmap.josm.data.osm.IRelation; 018import org.openstreetmap.josm.data.osm.IWay; 019import org.openstreetmap.josm.data.osm.PrimitiveId; 020import org.openstreetmap.josm.data.osm.QuadBucketPrimitiveStore; 021import org.openstreetmap.josm.data.osm.Storage; 022import org.openstreetmap.josm.tools.Logging; 023 024/** 025 * A class that stores data (essentially a simple {@link DataSet}) 026 * @author Taylor Smock 027 * @param <O> Type of OSM primitive 028 * @param <N> Type of node 029 * @param <W> Type of way 030 * @param <R> Type of relation 031 * @since 17862 032 */ 033class DataStore<O extends IPrimitive, N extends INode, W extends IWay<N>, R extends IRelation<?>> { 034 /** 035 * This literally only exists to make {@link QuadBucketPrimitiveStore#removePrimitive} public 036 * 037 * @param <N> The node type 038 * @param <W> The way type 039 * @param <R> The relation type 040 */ 041 static class LocalQuadBucketPrimitiveStore<N extends INode, W extends IWay<N>, R extends IRelation<?>> 042 extends QuadBucketPrimitiveStore<N, W, R> { 043 // Allow us to remove primitives (protected in {@link QuadBucketPrimitiveStore}) 044 @Override 045 public void removePrimitive(IPrimitive primitive) { 046 super.removePrimitive(primitive); 047 } 048 } 049 050 protected final LocalQuadBucketPrimitiveStore<N, W, R> store = new LocalQuadBucketPrimitiveStore<>(); 051 protected final Storage<O> allPrimitives = new Storage<>(new Storage.PrimitiveIdHash(), true); 052 // TODO what happens when I use hashCode? 053 protected final Set<Tile> addedTiles = Collections.synchronizedSet(new HashSet<>()); 054 protected final Map<PrimitiveId, O> primitivesMap = Collections.synchronizedMap(allPrimitives 055 .foreignKey(new Storage.PrimitiveIdHash())); 056 protected final Collection<DataSource> dataSources = new LinkedList<>(); 057 private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 058 059 public QuadBucketPrimitiveStore<N, W, R> getStore() { 060 return this.store; 061 } 062 063 public Storage<O> getAllPrimitives() { 064 return this.allPrimitives; 065 } 066 067 /** 068 * Get the primitives map. 069 * The returned map is a {@link Collections#synchronizedMap}. Please synchronize on it. 070 * @return The Primitives map. 071 */ 072 public Map<PrimitiveId, O> getPrimitivesMap() { 073 return this.primitivesMap; 074 } 075 076 public Collection<DataSource> getDataSources() { 077 return Collections.unmodifiableCollection(dataSources); 078 } 079 080 /** 081 * Add a datasource to this data set 082 * @param dataSource The data soure to add 083 */ 084 public void addDataSource(DataSource dataSource) { 085 this.dataSources.add(dataSource); 086 } 087 088 /** 089 * Add a primitive to this dataset 090 * @param primitive The primitive to remove 091 */ 092 protected void removePrimitive(O primitive) { 093 if (primitive == null) { 094 return; 095 } 096 try { 097 this.readWriteLock.writeLock().lockInterruptibly(); 098 if (this.allPrimitives.contains(primitive)) { 099 this.store.removePrimitive(primitive); 100 this.allPrimitives.remove(primitive); 101 this.primitivesMap.remove(primitive.getPrimitiveId()); 102 } 103 } catch (InterruptedException e) { 104 Logging.error(e); 105 Thread.currentThread().interrupt(); 106 } finally { 107 if (this.readWriteLock.isWriteLockedByCurrentThread()) { 108 this.readWriteLock.writeLock().unlock(); 109 } 110 } 111 } 112 113 /** 114 * Add a primitive to this dataset 115 * @param primitive The primitive to add 116 */ 117 protected void addPrimitive(O primitive) { 118 this.store.addPrimitive(primitive); 119 this.allPrimitives.add(primitive); 120 this.primitivesMap.put(primitive.getPrimitiveId(), primitive); 121 } 122 123 /** 124 * Get the read/write lock for this dataset 125 * @return The read/write lock 126 */ 127 protected ReentrantReadWriteLock getReadWriteLock() { 128 return this.readWriteLock; 129 } 130}