MATSIM
Id.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * IdI.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.api.core.v01;
22 
26 import org.matsim.core.gbl.Gbl;
27 import org.matsim.vehicles.Vehicle;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 
35 
44 public abstract class Id<T> implements Comparable<Id<T>> {
45 
46  private final static ConcurrentMap<Class<?>, ConcurrentMap<String, Id<?>>> cacheId = new ConcurrentHashMap<>();
47  private final static ConcurrentMap<Class<?>, List<Id<?>>> cacheIndex = new ConcurrentHashMap<>();
48 
52  public static void resetCaches() {
53  StackTraceElement[] elements = Thread.currentThread().getStackTrace();
54  boolean fromJUnit = false;
55  for (StackTraceElement element : elements) {
56  if (element.getClassName().contains("junit.")) {
57  fromJUnit = true;
58  break;
59  }
60  }
61  if (!fromJUnit) {
62  throw new RuntimeException("This method can only be called from JUnit-Tests, but not in normal code!");
63  }
64  cacheId.clear();
65  cacheIndex.clear();
66  }
67 
68  public static <T> Id<T> create(final long key, final Class<T> type) {
69  return create(Long.toString(key), type);
70  }
71 
72  public static <T> Id<T> create(final Id<?> id, final Class<T> type) {
73  if (id == null) {
74  return null;
75  }
76  return create(id.toString(), type);
77  }
78 
82  public static <T> Id<T> create(final String key, final Class<T> type) {
83  Gbl.assertNotNull(key);
84 
85  ConcurrentMap<String, Id<?>> mapId = cacheId.computeIfAbsent(type, k -> new ConcurrentHashMap<>(1000));
86 
87  Id<?> id = mapId.get(key);
88  if (id == null) {
89  //Double-Checked Locking works: mapId is concurrent and IdImpl is immutable
90  synchronized (mapId) {
91  id = mapId.get(key);
92  if (id == null) {
93  // cannot use cacheIndex.computeIfAbsent():
94  // split into cacheIndex.get() and put() so that mapIndex.add() "happens-before" mapIndex.get()
95  // alternatives:
96  // (1) synchronise mapIndex.get() calls (on mapIndex)
97  // (2) use cacheIndex.compute() instead of get() and put() ==> less readable code...
98  List<Id<?>> mapIndex = mapId.isEmpty() ? new ArrayList<>(1000) : cacheIndex.get(type);
99  int index = mapIndex.size();
100  id = new IdImpl<T>(key, index);
101  mapIndex.add(id);
102  cacheIndex.put(type, mapIndex);
103  mapId.put(key, id);
104  }
105  }
106  }
107  return (Id<T>)id;
108  }
109 
110  public abstract int index();
111 
112  public static <T> Id<T> get(int index, final Class<T> type) {
113  List<Id<?>> mapIndex = cacheIndex.get(type);
114  return mapIndex == null ? null : (Id<T>)mapIndex.get(index);
115  }
116 
117  public static <T> Id<T> get(String id, final Class<T> type) {
118  Map<String, Id<?>> mapId = cacheId.get(type);
119  return mapId == null ? null : (Id<T>)mapId.get(id);
120  }
121 
122  public static <T> int getNumberOfIds(final Class<T> type) {
123  Map<String, Id<?>> mapId = cacheId.get(type);
124  return mapId == null ? 0 : mapId.size();
125  }
126 
132  @Override
133  public int compareTo(Id<T> o) throws IllegalArgumentException {
134  return this.toString().compareTo(o.toString());
135 // return Integer.compare(this.index(), o.index()); // this would be more efficient, but changes some test results due to different ordering
136  }
137 
138  @Override
139  public boolean equals(Object obj) {
140  if (obj instanceof Id) {
141  return this.compareTo((Id) obj) == 0;
142  }
143  return false;
144 // return this == obj; // FIXME temporary relax the check until the Id migration has taken place
145  // all other objects have to be different by definition, as long as the cache is correctly implemented
146  }
147 
148 
158  private static class IdImpl<T> extends Id<T> {
159 
160  private final String id;
161  private final int index;
162 
163  /*package*/ IdImpl(final String id, final int index) {
164  this.id = id;
165  this.index = index;
166  }
167 
168  @Override
169  public int index() {
170  return this.index;
171  }
172 
173  @Override
174  public int hashCode() {
175  return this.id.hashCode();
176  // this.index would be an alternative implementation for the hashCode
177  }
178 
179  @Override
180  public String toString() {
181  return this.id;
182  }
183  }
184 
185  public static <T> String writeId( Id<T> id ) {
186  if ( id==null ) {
187  return "null" ;
188  }
189  return id.toString() ;
190  }
191 
192  // helper classes for some common cases:
193  public static Id<Person> createPersonId( final long key ) {
194  return create( key, Person.class ) ;
195  }
196  public static Id<Person> createPersonId( final Id<?> id ) {
197  return create( id, Person.class ) ;
198  }
199  public static Id<Person> createPersonId( final String str ) {
200  return create( str, Person.class ) ;
201  }
202  public static Id<Link> createLinkId( final long key ) {
203  return create( key, Link.class ) ;
204  }
205  public static Id<Link> createLinkId( final Id<?> id ) {
206  return create( id, Link.class ) ;
207  }
208  public static Id<Link> createLinkId( final String str ) {
209  return create( str, Link.class ) ;
210  }
211  public static Id<Node> createNodeId( final long key ) {
212  return create( key, Node.class ) ;
213  }
214  public static Id<Node> createNodeId( final Id<?> id ) {
215  return create( id, Node.class ) ;
216  }
217  public static Id<Node> createNodeId( final String str ) {
218  return create( str, Node.class ) ;
219  }
220  public static Id<Vehicle> createVehicleId( final long key ) {
221  return create( key, Vehicle.class ) ;
222  }
223  public static Id<Vehicle> createVehicleId( final Id<?> id ) {
224  return create( id, Vehicle.class ) ;
225  }
226  public static Id<Vehicle> createVehicleId( final String str ) {
227  return create( str, Vehicle.class ) ;
228  }
229 
230 }
static Id< Vehicle > createVehicleId(final String str)
Definition: Id.java:226
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
static< T > int getNumberOfIds(final Class< T > type)
Definition: Id.java:122
static final ConcurrentMap< Class<?>, ConcurrentMap< String, Id<?> > > cacheId
Definition: Id.java:46
static Id< Link > createLinkId(final String str)
Definition: Id.java:208
static void resetCaches()
Definition: Id.java:52
static Id< Vehicle > createVehicleId(final long key)
Definition: Id.java:220
static Id< Link > createLinkId(final long key)
Definition: Id.java:202
static Id< Person > createPersonId(final String str)
Definition: Id.java:199
static< T > String writeId(Id< T > id)
Definition: Id.java:185
static< T > Id< T > create(final long key, final Class< T > type)
Definition: Id.java:68
static final ConcurrentMap< Class<?>, List< Id<?> > > cacheIndex
Definition: Id.java:47
static void assertNotNull(Object obj)
Definition: Gbl.java:212
static Id< Node > createNodeId(final String str)
Definition: Id.java:217
int compareTo(Id< T > o)
Definition: Id.java:133
static Id< Person > createPersonId(final long key)
Definition: Id.java:193
static< T > Id< T > create(final Id<?> id, final Class< T > type)
Definition: Id.java:72
static Id< Person > createPersonId(final Id<?> id)
Definition: Id.java:196
static Id< Node > createNodeId(final Id<?> id)
Definition: Id.java:214
boolean equals(Object obj)
Definition: Id.java:139
static< T > Id< T > create(final String key, final Class< T > type)
Definition: Id.java:82
static Id< Node > createNodeId(final long key)
Definition: Id.java:211
static Id< Vehicle > createVehicleId(final Id<?> id)
Definition: Id.java:223
static Id< Link > createLinkId(final Id<?> id)
Definition: Id.java:205