From d1e1fb824e1848d074f2d0cef462ccc78c2ace95 Mon Sep 17 00:00:00 2001 From: Dmitry Toptygin Date: Thu, 17 Sep 2020 11:53:51 -0400 Subject: [PATCH] force loading of subclasses of AlarmCode to remove timing issues, fix handling of deprecated items by looking at full inheritance chain --- .../wlan/alarm/models/AlarmCode.java | 78 ++++++++++--------- .../TestVendorExtentions.java | 36 +++++++++ .../VendorExtendedAlarmCode.java | 8 +- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/alarm-models/src/main/java/com/telecominfraproject/wlan/alarm/models/AlarmCode.java b/alarm-models/src/main/java/com/telecominfraproject/wlan/alarm/models/AlarmCode.java index 5bde8ccc..838aae3d 100644 --- a/alarm-models/src/main/java/com/telecominfraproject/wlan/alarm/models/AlarmCode.java +++ b/alarm-models/src/main/java/com/telecominfraproject/wlan/alarm/models/AlarmCode.java @@ -4,11 +4,16 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.telecominfraproject.wlan.core.model.extensibleenum.EnumWithId; +import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; /** * All available Alarm codes that can be handled by the CloudSDK. @@ -36,6 +41,8 @@ import com.telecominfraproject.wlan.core.model.extensibleenum.EnumWithId; */ public class AlarmCode implements EnumWithId { + private static final Logger LOG = LoggerFactory.getLogger(AlarmCode.class); + private static Object lock = new Object(); private static final Map ELEMENTS = new ConcurrentHashMap<>(); private static final Map ELEMENTS_BY_NAME = new ConcurrentHashMap<>(); @@ -100,35 +107,17 @@ public class AlarmCode implements EnumWithId { UNSUPPORTED = new AlarmCode(-1, "UNSUPPORTED", "Alarm code is not supported by this release") ; - - public static AlarmCode[] validValues() { - if (VALID_VALUES.isEmpty()) { - synchronized (VALID_VALUES) { - if (VALID_VALUES.isEmpty()) { - for (AlarmCode met : AlarmCode.values()) { - // skip un-supported - if (isUnsupported(met)) { - continue; - } - // skip deprecated - try { - Field field = AlarmCode.class.getField(met.name()); - if (field.isAnnotationPresent(Deprecated.class)) { - continue; - } - } catch (NoSuchFieldException e) { - continue; - } catch (SecurityException e) { - continue; - } - - VALID_VALUES.put(met.getId(), met); - } - } + static { + //try to load all the subclasses explicitly - to avoid timing issues when items coming from subclasses may be registered some time later, after the parent class is loaded + Set> subclasses = BaseJsonModel.getReflections().getSubTypesOf(AlarmCode.class); + for(Class cls: subclasses) { + try { + Class.forName(cls.getName()); + } catch (ClassNotFoundException e) { + LOG.warn("Cannot load class {} : {}", cls.getName(), e); } } - return VALID_VALUES.values().toArray(new AlarmCode[VALID_VALUES.size()]); - } + } private final int id; private final String name; @@ -137,6 +126,9 @@ public class AlarmCode implements EnumWithId { protected AlarmCode(int id, String name, String description){ synchronized(lock) { + + LOG.debug("Registering AlarmCode by {} : {}", this.getClass().getSimpleName(), name); + this.id = id; this.name = name; this.description = description; @@ -157,15 +149,27 @@ public class AlarmCode implements EnumWithId { //add the item to VALID_VALUES if it's not UNSUPPORTED and not @Deprecated if(!name.equals("UNSUPPORTED")){ // skip deprecated - try { - Field field = AlarmCode.class.getField(name); - if (!field.isAnnotationPresent(Deprecated.class)) { - VALID_VALUES.put(id, this); + // make sure to look for the field definition in current class and in all its parents + Class cls = this.getClass(); + while(cls!=null) { + try { + Field field = cls.getField(name); + + if (!field.isAnnotationPresent(Deprecated.class)) { + VALID_VALUES.put(id, this); + } + + break; + + } catch (NoSuchFieldException e) { + //do nothing + } catch (SecurityException e) { + //do nothing } - } catch (NoSuchFieldException e) { - //do nothing - } catch (SecurityException e) { - //do nothing + + //prepare for the next iteration + cls = cls.getSuperclass(); + } } @@ -197,6 +201,10 @@ public class AlarmCode implements EnumWithId { return new ArrayList<>(ELEMENTS.values()).toArray(new AlarmCode[0]); } + public static AlarmCode[] validValues() { + return VALID_VALUES.values().toArray(new AlarmCode[VALID_VALUES.size()]); + } + public static AlarmCode getById(int enumId){ return ELEMENTS.get(enumId); } diff --git a/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/TestVendorExtentions.java b/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/TestVendorExtentions.java index e6a7dbe8..b53b9e15 100644 --- a/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/TestVendorExtentions.java +++ b/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/TestVendorExtentions.java @@ -1,13 +1,19 @@ package com.telecominfraproject.wlan.alarm.models.vendorextensions; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.HashMap; +import java.util.Map; + import org.junit.Test; import com.telecominfraproject.wlan.alarm.models.AlarmCode; import com.telecominfraproject.wlan.alarm.models.OriginatorType; import com.telecominfraproject.wlan.core.model.json.BaseJsonModel; +@SuppressWarnings("deprecation") public class TestVendorExtentions { @Test @@ -26,5 +32,35 @@ public class TestVendorExtentions { assertEquals(t3.toString(), t3d.toString()); } + + @Test + public void testVendorAlarmCode() { + Map mapping = new HashMap<>(); + for(AlarmCode c: VendorExtendedAlarmCode.values()) { + mapping.put(c.name(), c.getDescription()); + } + + assertNotNull(mapping.get(VendorExtendedAlarmCode.VENDOR_AC_A.name())); + assertNotNull(mapping.get(VendorExtendedAlarmCode.VENDOR_AC_DEPRECATED.name())); + } + + @Test + public void testValidVendorAlarmCode() { + Map mappingValid = new HashMap<>(); + + for(AlarmCode c: AlarmCode.validValues()) { + mappingValid.put(c.name(), c.getDescription()); + } + + assertNotNull(mappingValid.get(VendorExtendedAlarmCode.VENDOR_AC_A.name())); + assertNull(mappingValid.get(VendorExtendedAlarmCode.VENDOR_AC_DEPRECATED.name())); + } + + @Test + public void testGetVendorAlarmCode() { + assertNotNull(AlarmCode.getById(300)); + assertNotNull(AlarmCode.getByName("VENDOR_AC_A")); + assertNotNull(AlarmCode.getByName("VENDOR_AC_DEPRECATED")); + } } diff --git a/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/VendorExtendedAlarmCode.java b/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/VendorExtendedAlarmCode.java index dfcd6ae3..7f2b5116 100644 --- a/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/VendorExtendedAlarmCode.java +++ b/alarm-models/src/test/java/com/telecominfraproject/wlan/alarm/models/vendorextensions/VendorExtendedAlarmCode.java @@ -5,8 +5,12 @@ import com.telecominfraproject.wlan.alarm.models.AlarmCode; public class VendorExtendedAlarmCode extends AlarmCode { public static final AlarmCode - VENDOR_AC_A = new VendorExtendedAlarmCode(500, "VENDOR_AC_A", "description A") , - VENDOR_AC_B = new VendorExtendedAlarmCode(501, "VENDOR_AC_B", "description B") + VENDOR_AC_A = new VendorExtendedAlarmCode(300, "VENDOR_AC_A", "description A") , + VENDOR_AC_B = new VendorExtendedAlarmCode(301, "VENDOR_AC_B", "description B") ; + + @Deprecated + public static final AlarmCode + VENDOR_AC_DEPRECATED = new VendorExtendedAlarmCode(302, "VENDOR_AC_DEPRECATED", "description DEPRECATED") ; private VendorExtendedAlarmCode(int id, String name, String description) {