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 public final List<String> getTextualRepresentations()
423 {
424 if (this.abbreviation != null)
425 {
426 return Arrays.asList(new String[] {this.abbreviation});
427 }
428 if (localization.isDefault())
429 {
430 return getDefaultLocaleTextualRepresentations();
431 }
432 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
433 if (loc.length >= 3)
434 {
435 List<String> textList = new ArrayList<>();
436 for (int i = 2; i < loc.length; i++)
437 {
438 textList.add(loc[i].trim());
439 }
440 return textList;
441 }
442 if (loc.length >= 1)
443 {
444 return Arrays.asList(new String[] {loc[0].trim()});
445 }
446 return Arrays.asList(new String[] {this.abbreviationKey});
447 }
448
449
450
451
452
453
454 public final List<String> getDefaultLocaleTextualRepresentations()
455 {
456 if (this.abbreviation != null)
457 {
458 return Arrays.asList(new String[] {this.abbreviation});
459 }
460 if (this.cachedDefaultLocaleInfo.length >= 3)
461 {
462 List<String> textList = new ArrayList<>();
463 for (int i = 2; i < this.cachedDefaultLocaleInfo.length; i++)
464 {
465 textList.add(this.cachedDefaultLocaleInfo[i].trim());
466 }
467 return textList;
468 }
469 if (this.cachedDefaultLocaleInfo.length >= 1)
470 {
471 return Arrays.asList(new String[] {this.cachedDefaultLocaleInfo[0].trim()});
472 }
473 return Arrays.asList(new String[] {this.abbreviationKey});
474 }
475
476
477
478
479
480
481 public final String getDefaultTextualRepresentation()
482 {
483 if (this.abbreviation != null)
484 {
485 return this.abbreviation;
486 }
487 if (localization.isDefault())
488 {
489 return getDefaultLocaleTextualRepresentation();
490 }
491 String[] loc = localization.getString(this.abbreviationKey).split("\\|");
492 if (loc.length >= 3)
493 {
494 return loc[2].trim();
495 }
496 if (loc.length >= 1)
497 {
498 return loc[0].trim();
499 }
500 return this.abbreviationKey;
501 }
502
503
504
505
506
507
508 public final String getDefaultLocaleTextualRepresentation()
509 {
510 if (this.abbreviation != null)
511 {
512 return this.abbreviation;
513 }
514 if (this.cachedDefaultLocaleInfo.length >= 3)
515 {
516 return this.cachedDefaultLocaleInfo[2].trim();
517 }
518 if (this.cachedDefaultLocaleInfo.length >= 1)
519 {
520 return this.cachedDefaultLocaleInfo[0].trim();
521 }
522 return this.abbreviationKey;
523 }
524
525
526
527
528 @SuppressWarnings("checkstyle:designforextension")
529 public Scale getScale()
530 {
531 return this.scale;
532 }
533
534
535
536
537 public final UnitSystem getUnitSystem()
538 {
539 return this.unitSystem;
540 }
541
542
543
544
545 public abstract U getStandardUnit();
546
547
548
549
550
551 public abstract String getSICoefficientsString();
552
553
554
555
556 public final SICoefficients getSICoefficients()
557 {
558 return this.siCoefficients;
559 }
560
561
562
563
564
565 public final boolean isBaseSIUnit()
566 {
567 return this.baseSIUnit;
568 }
569
570
571
572
573
574 public static Set<Unit<?>> lookupUnitWithSICoefficients(final String normalizedSICoefficientsString)
575 {
576 if (!standardUnitsInitialized)
577 {
578 initializeStandardUnits();
579 }
580 if (SI_UNITS.containsKey(normalizedSICoefficientsString))
581 {
582 return new HashSet<Unit<?>>(SI_UNITS.get(normalizedSICoefficientsString).values());
583 }
584 return new HashSet<Unit<?>>();
585 }
586
587
588
589
590
591 public static Set<Unit<?>> lookupOrCreateUnitWithSICoefficients(final String normalizedSICoefficientsString)
592 {
593 if (!standardUnitsInitialized)
594 {
595 initializeStandardUnits();
596 }
597 if (SI_UNITS.containsKey(normalizedSICoefficientsString))
598 {
599 return new HashSet<Unit<?>>(SI_UNITS.get(normalizedSICoefficientsString).values());
600 }
601 SIUnit unit = new SIUnit("SIUnit." + normalizedSICoefficientsString);
602 Set<Unit<?>> unitSet = new HashSet<Unit<?>>();
603 unitSet.add(unit);
604 return unitSet;
605 }
606
607
608
609
610
611 public static SIUnit lookupOrCreateSIUnitWithSICoefficients(final String normalizedSICoefficientsString)
612 {
613 if (!standardUnitsInitialized)
614 {
615 initializeStandardUnits();
616 }
617 if (SI_UNITS.containsKey(normalizedSICoefficientsString)
618 && SI_UNITS.get(normalizedSICoefficientsString).containsKey(SIUnit.class))
619 {
620 return (SIUnit) SI_UNITS.get(normalizedSICoefficientsString).get(SIUnit.class);
621 }
622 SIUnit unit = new SIUnit("SIUnit." + normalizedSICoefficientsString);
623 return unit;
624 }
625
626
627 @Override
628 public final String toString()
629 {
630 return getAbbreviation();
631 }
632
633
634
635
636
637 public final int generateHashCode()
638 {
639 final int prime = 31;
640 int result = 1;
641 result = prime * result + ((this.abbreviation == null) ? 0 : this.abbreviation.hashCode());
642 result = prime * result + ((this.abbreviationKey == null) ? 0 : this.abbreviationKey.hashCode());
643 result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
644 return result;
645 }
646
647
648 @SuppressWarnings("checkstyle:designforextension")
649 @Override
650 public int hashCode()
651 {
652 return this.cachedHashCode;
653 }
654
655
656 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
657 @Override
658 public boolean equals(final Object obj)
659 {
660 if (this == obj)
661 return true;
662 if (obj == null)
663 return false;
664 if (getClass() != obj.getClass())
665 return false;
666 Unit<?> other = (Unit<?>) obj;
667 if (this.abbreviation == null)
668 {
669 if (other.abbreviation != null)
670 return false;
671 }
672 else if (!this.abbreviation.equals(other.abbreviation))
673 return false;
674 if (this.abbreviationKey == null)
675 {
676 if (other.abbreviationKey != null)
677 return false;
678 }
679 else if (!this.abbreviationKey.equals(other.abbreviationKey))
680 return false;
681 if (this.name == null)
682 {
683 if (other.name != null)
684 return false;
685 }
686 else if (!this.name.equals(other.name))
687 return false;
688 return true;
689 }
690
691
692
693
694
695
696
697 public abstract boolean equalsIgnoreNaming(Object obj);
698
699 }