@@ -636,29 +636,31 @@ public List<DataType> getDataTypesByBaseName(String dataTypeName) {
636
636
list .add (baseType );
637
637
}
638
638
639
- List <DataType > relatedNameDataTypes = conflictMap .getDataTypesForBaseName (baseName );
639
+ List <DataType > relatedNameDataTypes = conflictMap .getDataTypesByBaseName (baseName );
640
640
list .addAll (relatedNameDataTypes );
641
641
return list ;
642
642
}
643
643
644
644
/**
645
- * Class to handle complexities of having a map as the value in a LazyLoadingCachingMap
646
- * This map uses data type's base name as the key (i.e. all .conflict suffixex stripped off.)
647
- * The value is another map that maps the actual data type's name to the datatype . This map
645
+ * Class to handle the complexities of having a map as the value in a LazyLoadingCachingMap
646
+ * This map uses the data type's base name as the key (i.e. all .conflict suffixes stripped off.)
647
+ * The value is another map that maps the actual data type's name to the data type . This map
648
648
* effectively provides an efficient way to get all data types in a category that have the
649
649
* same name, but possibly have had their name modified (by appending .conflict) to get around
650
650
* the requirement that names have to be unique in the same category.
651
651
*/
652
- class ConflictMap extends LazyLoadingCachingMap <String , Map <String , DataType >> {
652
+ private class ConflictMap extends LazyLoadingCachingMap <String , Map <String , DataType >> {
653
653
654
654
ConflictMap (Lock lock ) {
655
655
super (lock );
656
656
}
657
657
658
658
/**
659
659
* Creates a map of all data types whose name has a .conflict suffix where the key
660
- * is the base name and the value is a map of actual name to data type. This mapping is
661
- * maintained as a lazy cache map.
660
+ * is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name to data type. This mapping is
661
+ * maintained as a lazy cache map. This is only called by the super class when the
662
+ * cached needs to be populated and we are depending on it to acquire the necessary
663
+ * database lock. (See {@link LazyLoadingCachingMap#loadMap()}
662
664
* @return the loaded map
663
665
*/
664
666
@ Override
@@ -670,10 +672,7 @@ protected Map<String, Map<String, DataType>> loadMap() {
670
672
if (isConflictName (dataTypeName )) {
671
673
String baseName = getBaseName (dataTypeName );
672
674
Map <String , DataType > innerMap = map .get (baseName );
673
- if (innerMap == null ) {
674
- innerMap = new HashMap <>();
675
- map .put (baseName , innerMap );
676
- }
675
+ map .computeIfAbsent (baseName , b -> new HashMap <>());
677
676
innerMap .put (dataTypeName , dataType );
678
677
}
679
678
}
@@ -682,28 +681,27 @@ protected Map<String, Map<String, DataType>> loadMap() {
682
681
683
682
/**
684
683
* Adds the data type to the conflict mapping structure. If the mapping is currently not
685
- * loaded then this method can safely do nothing.
684
+ * loaded then this method can safely do nothing. This method is synchronized to provide
685
+ * thread safe access/manipulation of the map.
686
686
* @param dataType the data type to add to the mapping if the mapping is already loaded
687
687
*/
688
688
synchronized void addDataType (DataType dataType ) {
689
+ // if the cache is not currently populated, don't need to do anything
689
690
Map <String , Map <String , DataType >> map = getMap ();
690
691
if (map == null ) {
691
692
return ;
692
693
}
693
694
694
695
String dataTypeName = dataType .getName ();
695
696
String baseName = getBaseName (dataTypeName );
696
- Map <String , DataType > innerMap = map .get (baseName );
697
- if (innerMap == null ) {
698
- innerMap = new HashMap <>();
699
- put (baseName , innerMap );
700
- }
697
+ Map <String , DataType > innerMap = map .computeIfAbsent (baseName , b -> new HashMap <>());
701
698
innerMap .put (dataTypeName , dataType );
702
699
}
703
700
704
701
/**
705
702
* Removes the data type with the given name from the conflict mapping structure. If the
706
- * mapping is currently not loaded then this method can safely do nothing.
703
+ * mapping is currently not loaded then this method can safely do nothing. This method is
704
+ * synchronized to provide thread safe access/manipulate of the map.
707
705
* @param dataTypeName the name of the data type to remove from this mapping
708
706
*/
709
707
synchronized void removeDataTypeName (String dataTypeName ) {
@@ -725,11 +723,19 @@ synchronized void removeDataTypeName(String dataTypeName) {
725
723
* @return a list of all conflict named data types that would have the given base name if
726
724
* no conflicts existed
727
725
*/
728
- List <DataType > getDataTypesForBaseName (String baseName ) {
726
+ List <DataType > getDataTypesByBaseName (String baseName ) {
727
+
728
+ // Note that the following call to get MUST NOT be in a synchronized block because
729
+ // it may trigger a loading of the cache which requires a database lock and you
730
+ // can't be synchronized on this class when acquiring a database lock or else a
731
+ // deadlock will occur.
729
732
Map <String , DataType > map = get (baseName );
730
733
if (map == null ) {
731
734
return Collections .emptyList ();
732
735
}
736
+
737
+ // the following must be synchronized so that the implied iterator can complete without
738
+ // another thread changing the map's values.
733
739
synchronized (this ) {
734
740
return new ArrayList <>(map .values ());
735
741
}
0 commit comments