1 package org.djunits.unit;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.djunits.locale.Localization;
13 import org.djunits.unit.scale.Scale;
14 import org.djunits.unit.scale.StandardScale;
15 import org.djunits.unit.unitsystem.UnitSystem;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 public abstract class Unit<U extends Unit<U>> implements Serializable
31 {
32
33 private static final long serialVersionUID = 20140607;
34
35
36 private final String abbreviationKey;
37
38
39
40
41
42 private final String name;
43
44
45
46
47
48 private final String abbreviation;
49
50
51 private final UnitSystem unitSystem;
52
53
54 private final Scale scale;
55
56
57 private SICoefficients siCoefficients;
58
59
60 private static final Map<String, SICoefficients> SI_COEFFICIENTS = new HashMap<String, SICoefficients>();
61
62
63 private static final Map<String, Map<Class<Unit<?>>, Unit<?>>> SI_UNITS =
64 new HashMap<String, Map<Class<Unit<?>>, Unit<?>>>();
65
66
67 private static final Map<String, Set<Unit<?>>> UNITS = new HashMap<String, Set<Unit<?>>>();
68
69
70 private static boolean standardUnitsInitialized = false;
71
72
73 private boolean baseSIUnit;
74
75
76 public static final String[] STANDARD_UNITS = new String[] {"AbsoluteTemperatureUnit", "AccelerationUnit", "AngleSolidUnit",
77 "AngleUnit", "AreaUnit", "DensityUnit", "DimensionlessUnit", "DirectionUnit", "DurationUnit",
78 "ElectricalChargeUnit", "ElectricalCurrentUnit", "ElectricalPotentialUnit", "ElectricalResistanceUnit",
79 "EnergyUnit", "FlowMassUnit", "FlowVolumeUnit", "ForceUnit", "FrequencyUnit", "LengthUnit", "LinearDensityUnit",
80 "MassUnit", "MoneyUnit", "MoneyPerAreaUnit", "MoneyPerEnergyUnit", "MoneyPerLengthUnit", "MoneyPerMassUnit",
81 "MoneyPerDurationUnit", "MoneyPerVolumeUnit", "PositionUnit", "PowerUnit", "PressureUnit", "SpeedUnit",
82 "TemperatureUnit", "TimeUnit", "TorqueUnit", "VolumeUnit"};
83
84
85 private final int cachedHashCode;
86
87
88 private static Localization localization = new Localization("localeunit");
89
90
91 private String[] cachedDefaultLocaleInfo;
92
93
94
95
96 private static void initializeStandardUnits()
97 {
98 for (String className : STANDARD_UNITS)
99 {
100 try
101 {
102 Class.forName("org.djunits.unit." + className);
103 }
104 catch (Exception exception)
105 {
106
107 System.err.println("Could not load class org.djunits.unit." + className);
108 }
109 }
110 standardUnitsInitialized = true;
111 }
112
113
114
115
116
117
118 protected Unit(final String abbreviationKey, final UnitSystem unitSystem)
119 {
120 this.scale = StandardScale.SCALE;
121 this.baseSIUnit = true;
122 this.abbreviationKey = abbreviationKey;
123 this.name = null;
124 this.abbreviation = null;
125 this.cachedDefaultLocaleInfo = localization.getDefaultString(this.abbreviationKey).split("\\|");
126 this.unitSystem = unitSystem;
127 this.cachedHashCode = generateHashCode();
128 try
129 {
130 addUnit(this);
131 }
132 catch (UnitException ue)
133 {
134
135 }
136 }
137
138
139
140
141
142
143
144
145
146 protected Unit(final String abbreviationKey, final UnitSystem unitSystem, final Scale scale)
147 {
148 this.scale = scale;
149 this.baseSIUnit = scale.isBaseSIScale();
150 this.abbreviationKey = abbreviationKey;
151 this.name = null;
152 this.abbreviation = null;
153 this.cachedDefaultLocaleInfo = localization.getDefaultString(this.abbreviationKey).split("\\|");
154 this.unitSystem = unitSystem;
155 this.cachedHashCode = generateHashCode();
156 try
157 {
158 addUnit(this);
159 }
160 catch (UnitException ue)
161 {
162
163 }
164 }
165
166
167
168
169
170
171
172
173
174 protected Unit(final String name, final String abbreviation, final UnitSystem unitSystem)
175 {
176 this.scale = StandardScale.SCALE;
177 this.baseSIUnit = true;
178 this.abbreviationKey = null;
179 this.name = name;
180 this.abbreviation = abbreviation;
181 this.unitSystem = unitSystem;
182 this.cachedHashCode = generateHashCode();
183 try
184 {
185 addUnit(this);
186 }
187 catch (UnitException ue)
188 {
189 throw new RuntimeException(ue);
190 }
191 }
192
193
194
195
196
197
198
199
200
201
202 protected Unit(final String name, final String abbreviation, final UnitSystem unitSystem, final Scale scale)
203 {
204 this.scale = scale;
205 this.baseSIUnit = scale.isBaseSIScale();
206 this.abbreviationKey = null;
207 this.name = name;
208 this.abbreviation = abbreviation;
209 this.unitSystem = unitSystem;
210 this.cachedHashCode = generateHashCode();
211 try
212 {
213 addUnit(this);
214 }
215 catch (UnitException ue)
216 {
217 throw new RuntimeException(ue);
218 }
219 }
220
221
222
223
224
225 public final boolean isLocalizable()
226 {
227 return this.abbreviationKey != null;
228 }
229
230
231
232
233
234
235
236 private void addUnit(final Unit<U> unit) throws UnitException
237 {
238 if (!UNITS.containsKey(unit.getClass().getSimpleName()))
239 {
240 UNITS.put(unit.getClass().getSimpleName(), new HashSet<Unit<?>>());
241 }
242 UNITS.get(unit.getClass().getSimpleName()).add(unit);
243
244
245 String siCoefficientsString = SICoefficients.normalize(getSICoefficientsString()).toString();
246 if (SI_COEFFICIENTS.containsKey(siCoefficientsString))
247 {
248 this.siCoefficients = SI_COEFFICIENTS.get(siCoefficientsString);
249 }
250 else
251 {
252 this.siCoefficients = new SICoefficients(SICoefficients.parse(siCoefficientsString));
253 SI_COEFFICIENTS.put(siCoefficientsString, this.siCoefficients);
254 }
255
256
257 Map<Class<Unit<?>>, Unit<?>> unitMap = SI_UNITS.get(siCoefficientsString);
258 if (unitMap == null)
259 {
260 unitMap = new HashMap<Class<Unit<?>>, Unit<?>>();
261 SI_UNITS.put(siCoefficientsString, unitMap);
262 }
263 if (!unitMap.containsKey(unit.getClass()))
264 {
265 @SuppressWarnings("unchecked")
266 Class<Unit<?>> clazz = (Class<Unit<?>>) unit.getClass();
267 if (this.getStandardUnit() == null)
268 {
269 unitMap.put(clazz, this);
270 }
271 else
272 {
273 unitMap.put(clazz, this.getStandardUnit());
274 }
275 }
276 }
277
278
279
280
281
282
283
284
285 @SuppressWarnings("unchecked")
286 public static <V extends Unit<V>> Set<V> getUnits(final Class<V> unitClass)
287 {
288 if (!standardUnitsInitialized)
289 {
290 initializeStandardUnits();
291 }
292 Set<V> returnSet = new HashSet<V>();
293 if (UNITS.containsKey(unitClass.getSimpleName()))
294 {
295 for (Unit<?> unit : UNITS.get(unitClass.getSimpleName()))
296 {
297 returnSet.add((V) unit);
298 }
299 }
300 return returnSet;
301 }
302
303
304
305
306
307
308 @SuppressWarnings("unchecked")
309 public final Set<Unit<U>> getAllUnitsOfThisType()
310 {
311 if (!standardUnitsInitialized)
312 {
313 initializeStandardUnits();
314 }
315 Set<Unit<U>> returnSet = new HashSet<Unit<U>>();
316 if (UNITS.containsKey(this.getClass().getSimpleName()))
317 {
318 for (Unit<?> unit : UNITS.get(this.getClass().getSimpleName()))
319 {
320 returnSet.add((Unit<U>) unit);
321 }
322 }
323 return returnSet;
324 }
325
326
327
328
329 public final String getName()
330 {
331 if (this.name != null)
332 {
333 return this.name;
334 }
335 if (localization.isDefault())
336 {
337 return getDefaultLocaleName();
338 }
339 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
340 if (loc.length >= 2)
341 {
342 return loc[1].trim();
343 }
344 if (loc.length >= 1)
345 {
346 return loc[0].trim();
347 }
348 return this.abbreviationKey;
349 }
350
351
352
353
354 public final String getDefaultLocaleName()
355 {
356 if (this.name != null)
357 {
358 return this.name;
359 }
360 if (this.cachedDefaultLocaleInfo.length >= 2)
361 {
362 return this.cachedDefaultLocaleInfo[1].trim();
363 }
364 if (this.cachedDefaultLocaleInfo.length >= 1)
365 {
366 return this.cachedDefaultLocaleInfo[0].trim();
367 }
368 return this.abbreviationKey;
369 }
370
371
372
373
374 public final String getAbbreviation()
375 {
376 if (this.abbreviation != null)
377 {
378 return this.abbreviation;
379 }
380 if (localization.isDefault())
381 {
382 return getDefaultLocaleAbbreviation();
383 }
384 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
385 if (loc.length >= 1)
386 {
387 return loc[0].trim();
388 }
389 return this.abbreviationKey;
390 }
391
392
393
394
395 public final String getDefaultLocaleAbbreviation()
396 {
397 if (this.abbreviation != null)
398 {
399 return this.abbreviation;
400 }
401 if (this.cachedDefaultLocaleInfo.length >= 1)
402 {
403 return this.cachedDefaultLocaleInfo[0].trim();
404 }
405 return this.abbreviationKey;
406 }
407
408
409
410
411
412 public final String getAbbreviationKey()
413 {
414 return this.abbreviationKey;
415 }
416
417
418
419
420
421
422
423 public final List<String> getTextualRepresentations()
424 {
425 if (this.abbreviation != null)
426 {
427 return Arrays.asList(new String[] {this.abbreviation});
428 }
429 if (localization.isDefault())
430 {
431 return getDefaultLocaleTextualRepresentations();
432 }
433 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
434 if (loc.length >= 3)
435 {
436 List<String> textList = new ArrayList<>();
437 for (int i = 2; i < loc.length; i++)
438 {
439 textList.add(loc[i].trim());
440 }
441 return textList;
442 }
443 if (loc.length >= 1)
444 {
445 return Arrays.asList(new String[] {loc[0].trim()});
446 }
447 return Arrays.asList(new String[] {this.abbreviationKey});
448 }
449
450
451
452
453
454
455
456
457 public final List<String> getDefaultLocaleTextualRepresentations()
458 {
459 if (this.abbreviation != null)
460 {
461 return Arrays.asList(new String[] {this.abbreviation});
462 }
463 if (this.cachedDefaultLocaleInfo.length >= 3)
464 {
465 List<String> textList = new ArrayList<>();
466 for (int i = 2; i < this.cachedDefaultLocaleInfo.length; i++)
467 {
468 textList.add(this.cachedDefaultLocaleInfo[i].trim());
469 }
470 return textList;
471 }
472 if (this.cachedDefaultLocaleInfo.length >= 1)
473 {
474 return Arrays.asList(new String[] {this.cachedDefaultLocaleInfo[0].trim()});
475 }
476 return Arrays.asList(new String[] {this.abbreviationKey});
477 }
478
479
480
481
482
483
484
485 public final String getDefaultTextualRepresentation()
486 {
487 if (this.abbreviation != null)
488 {
489 return this.abbreviation;
490 }
491 if (localization.isDefault())
492 {
493 return getDefaultLocaleTextualRepresentation();
494 }
495 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
496 if (loc.length >= 3)
497 {
498 return loc[2].trim();
499 }
500 if (loc.length >= 1)
501 {
502 return loc[0].trim();
503 }
504 return this.abbreviationKey;
505 }
506
507
508
509
510
511
512
513
514 public final String getDefaultLocaleTextualRepresentation()
515 {
516 if (this.abbreviation != null)
517 {
518 return this.abbreviation;
519 }
520 if (this.cachedDefaultLocaleInfo.length >= 3)
521 {
522 return this.cachedDefaultLocaleInfo[2].trim();
523 }
524 if (this.cachedDefaultLocaleInfo.length >= 1)
525 {
526 return this.cachedDefaultLocaleInfo[0].trim();
527 }
528 return this.abbreviationKey;
529 }
530
531
532
533
534 @SuppressWarnings("checkstyle:designforextension")
535 public Scale getScale()
536 {
537 return this.scale;
538 }
539
540
541
542
543 public final UnitSystem getUnitSystem()
544 {
545 return this.unitSystem;
546 }
547
548
549
550
551 public abstract U getStandardUnit();
552
553
554
555
556
557 public abstract String getSICoefficientsString();
558
559
560
561
562 public final SICoefficients getSICoefficients()
563 {
564 return this.siCoefficients;
565 }
566
567
568
569
570
571 public final boolean isBaseSIUnit()
572 {
573 return this.baseSIUnit;
574 }
575
576
577
578
579
580 public static Set<Unit<?>> lookupUnitWithSICoefficients(final String normalizedSICoefficientsString)
581 {
582 if (!standardUnitsInitialized)
583 {
584 initializeStandardUnits();
585 }
586 if (SI_UNITS.containsKey(normalizedSICoefficientsString))
587 {
588 return new HashSet<Unit<?>>(SI_UNITS.get(normalizedSICoefficientsString).values());
589 }
590 return new HashSet<Unit<?>>();
591 }
592
593
594
595
596
597 public static Set<Unit<?>> lookupOrCreateUnitWithSICoefficients(final String normalizedSICoefficientsString)
598 {
599 if (!standardUnitsInitialized)
600 {
601 initializeStandardUnits();
602 }
603 if (SI_UNITS.containsKey(normalizedSICoefficientsString))
604 {
605 return new HashSet<Unit<?>>(SI_UNITS.get(normalizedSICoefficientsString).values());
606 }
607 SIUnit unit = new SIUnit("SIUnit." + normalizedSICoefficientsString);
608 Set<Unit<?>> unitSet = new HashSet<Unit<?>>();
609 unitSet.add(unit);
610 return unitSet;
611 }
612
613
614
615
616
617 public static SIUnit lookupOrCreateSIUnitWithSICoefficients(final String normalizedSICoefficientsString)
618 {
619 if (!standardUnitsInitialized)
620 {
621 initializeStandardUnits();
622 }
623 if (SI_UNITS.containsKey(normalizedSICoefficientsString)
624 && SI_UNITS.get(normalizedSICoefficientsString).containsKey(SIUnit.class))
625 {
626 return (SIUnit) SI_UNITS.get(normalizedSICoefficientsString).get(SIUnit.class);
627 }
628 SIUnit unit = new SIUnit("SIUnit." + normalizedSICoefficientsString);
629 return unit;
630 }
631
632
633 @Override
634 public final String toString()
635 {
636 return getAbbreviation();
637 }
638
639
640
641
642
643 public final int generateHashCode()
644 {
645 final int prime = 31;
646 int result = 1;
647 result = prime * result + ((this.abbreviation == null) ? 0 : this.abbreviation.hashCode());
648 result = prime * result + ((this.abbreviationKey == null) ? 0 : this.abbreviationKey.hashCode());
649 result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
650 return result;
651 }
652
653
654 @SuppressWarnings("checkstyle:designforextension")
655 @Override
656 public int hashCode()
657 {
658 return this.cachedHashCode;
659 }
660
661
662 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
663 @Override
664 public boolean equals(final Object obj)
665 {
666 if (this == obj)
667 return true;
668 if (obj == null)
669 return false;
670 if (getClass() != obj.getClass())
671 return false;
672 Unit<?> other = (Unit<?>) obj;
673 if (this.abbreviation == null)
674 {
675 if (other.abbreviation != null)
676 return false;
677 }
678 else if (!this.abbreviation.equals(other.abbreviation))
679 return false;
680 if (this.abbreviationKey == null)
681 {
682 if (other.abbreviationKey != null)
683 return false;
684 }
685 else if (!this.abbreviationKey.equals(other.abbreviationKey))
686 return false;
687 if (this.name == null)
688 {
689 if (other.name != null)
690 return false;
691 }
692 else if (!this.name.equals(other.name))
693 return false;
694 return true;
695 }
696
697
698
699
700
701
702
703 public abstract boolean equalsIgnoreNaming(Object obj);
704
705 }