Class cast exception due to different class loaders

In our Kafka module, there is a audit profile type that allows for splitting of events, one way goes to local DB, the other goes to Kafka. When I install the module once, this works as expected without error.

Audit Log Splitter Profile Type

However, if I leave everything installed as-is and simply upgrade the module I start to have class cast exception errors and the reason is because there are different class loaders in play. As far as I can tell there is a class loader associated with the audit profile and if the main module changes that instance of the class loader is then different that what is used by the gateway hook, gateway script module, etc.

Fresh install - Audit Events have a consistent class loader

After Module Update - Multiple class loaders are present

Interestingly, I can see that the class loader instance which would come from AuditRecord is the same as before the module was updated.

So for a module which establishes an instance of something that will end up using a different class loader after the module gets updated later on, what is a good way to prevent class cast errors due to different class loaders?

Thanks,

Nick

This means your module has a ClassLoader leak, i.e. if your were to simply uninstall it there would still be references to classes from your module, and its ClassLoader, hanging around in memory.

Usually this means you didn’t unregistered all the things you registered and/or shutdown all the things you may have started (background threads or process, for example).

@Kevin.Herron yeah, if I completely removed the module, the instance of the audit profile would still be there.

If I can get the audit profile (by name or by type) would it be sufficient to use the shut down and start up methods on the AuditProfile?

I believe if I am removing the module altogether I should remove the audit profile but if I'm just updating the module the audit profile should remain in place.

Nick

"Updating" a module is shutting down and removing the old one and installing a new one. If the old one doesn't remove or shutdown everything then you leak.

It looks like AuditManager doesn't have a corresponding removeAuditProfileType, which is a failure on our part that we'll have to fix. There's probably not much you can do to work around this right now.

There's no update in place. You must remove everything during module shutdown, since you don't know if a replacement is coming. You also may have new code for the established instances that won't work if not replaced.

1 Like

@Kevin.Herron actually if there was an interface for audits, that might make this easier. It would be something similar to AlarmListener but for Audits. Something like "onAudit" and then we could just define where to send that data after that and it would be done in the gateway script module so start up and shut down would already be in place.

Really the only reason I am setting up an audit profile at all is just so I can capture the AuditRecord.

Something like this but for Audit records instead:

    private void setupAlarmManager(KafkaSettingsRecord config) {
        alarmListener = new AlarmListener() {
            @Override
            public void onActive(AlarmEvent alarmEvent) {
                scriptModule.sendEquipmentAlarm(alarmEvent, alarmEvent.getActiveData(), config);
            }

            @Override
            public void onClear(AlarmEvent alarmEvent) {
                scriptModule.sendEquipmentAlarm(alarmEvent, alarmEvent.getClearedData(), config);
            }

            @Override
            public void onAcknowledge(AlarmEvent alarmEvent) {
                scriptModule.sendEquipmentAlarm(alarmEvent, alarmEvent.getAckData(), config);
            }
        };

Nick

Consider building an "export" jar that will load once for the gateway's lifetime. Have it implement an audit profile that can be registered, but delegates to a separate class in your main jar that is supplied or replaced on gateway hook startup. Poor man's proper extension point. (:

1 Like

Right now we have alarms and tags working fine so we'll just be disabling sending of audit data to kafka.

If the module SDK is updated to have a method to remove an audit profile type or have an interface to grab the audit event without having to create a new audit type, we'll come back and update the gateway hook and/or gateway script module.

Added this to the features and ideas page here.

Nick

@Kevin.Herron thinking about this a bit more, if a method is added to allow an audit profile type to be removed, it will need to consider how to handle the instances of that type which are specified in the gateway and in the designer. Otherwise once the audit type is removed errors will happen when the gateway or designer goes to use a audit sink that is no longer there.

For our needs, an audit listener would be the simplest so we don't even have to handle an audit profile type.

Thanks,

Nick