Create a new module instance from another module

Hello!

For one of my client’s needs, I would like to be able to create new module instances outside Ignition using http requests. I know this is something that isn’t really possible normally so that’s why I wanted to share my thoughts with you about what could be the best solution.

I have a dedicated module that is handling every request to do the interface between calls and ignition. I receive any needed properties in JSON format and after that I would be able to create a new persistence record of another module (already installed on my gateway). My problem is that I do not have access to the custom Persistence Record class of the module that I need to create an instance of. I cannot instantiate a PersistenceRecord and then modify it to match my needed record format.

E.g.: It is possible to create a new device, by creating a new instance of Device settings record and then add some specs to it (add META fields for each attributes).

DeviceSettingsRecord deviceRecord = context.getPersistenceInterface()
                            .createNew(DeviceSettingsRecord.META, session.getDataSet());

So, i wanted to know if anybody has any idea on how could iImanage to do that? Otherwise, I had the idea of instead of creating the module directly from another module to just send like an “event” to tell to the module to create a new instance of itself. I’ve look into some example demonstrating alarm notifications but it seems not appropriate and over complicated for what I am trying to achieve. My other lead would be to make a notification through a tag change and then pass the information inside tag’s metadata. This should work, but that seems a little too far-fetched to me.

What’s your opinion about that?

There's never but one instance of any module running in Ignition. Many modules support multiple instances of objects they support, but that is all internal to the module. OPC driver modules cooperate with the OPC Server module to expose instance management in the OPC server's configuration pages, but each driver manages their own persistence records. The OPC server module makes the DeviceSettingsRecord while the driver privately makes its own *SettingsRecord with the extra information it needs. Drivers can do anything they want with their own records, and don't even have to limit themselves to one extra type. You simply cannot make any assumptions about what they need.

Ignition exposes device management script functions that know about the drivers supplied by IA. You might want to look at what's possible with those.

2 Likes

Thanks for the quick reply @pturmel,. Indeed, I didn’t express myself properly. I know there can be only one “instance” but what I am trying to achieve is to add a new record to my module so that my RecordListener triggers recordAdded(), recordUpdated() or recordDeleted() when I add a new one even if it’s not directly from Ignition. That’s what I’m calling instances (see Creates multiple instances of records).

What I was saying it’s that I know it’s possible with drivers (because I’m already doing it) but now I want to do the same with “normal” modules (that are juste using a simple GatewayHook).

Are you also creating the inner PersistenceRecord for the driver instances? Driver instances generally won't work properly without.

Anyway, you should be able to get a reference to a module via the Module Manager, and then get its classloader. From there, reflection should make it possible for you to access that module's Settings Records.

2 Likes

ModuleManager.resolveClass(classname), or ModuleManager.getModule(moduleId).getHook() are things to look into. Or perhaps GatewayContext.getSchemaUpdater().findRecordMeta(tableName).

If you mark whatever module you’re trying to create records for as a dependency of your module, you’ll be in the correct classloader already and not have to perform (as many) shenanigans to get access to it.
Make sure you call GatewayContext.getPersistenceInterface().notifyRecordAdded(PersistentRecord) after you’ve created (and saved) your records.

2 Likes

Hi @PGriffith, thanks for the tip, I managed to do exactly what I wanted.

Here’s my solution if that can help some:

            SRecordMeta<? extends SRecordInstance> srMeta = context.getSchemaUpdater().findRecordMeta("<record_table_name>");
            assert srMeta != null;
            RecordMeta newMeta = new RecordMeta(srMeta.getUserClass(), "<record_table_name>");

            PersistentRecord r = context.getPersistenceInterface().createNew(newMeta);
            List<SFieldMeta> fieldList = srMeta.getFieldMetas();
            for(String paramName : params.names()){
                for(SFieldMeta field : fieldList){
                    if(field.getFieldName().equalsIgnoreCase(paramName)){
                        r.setString(field, params.get(paramName).asString());
                    }
                }
            }

            context.getPersistenceInterface().save(r);
            context.getPersistenceInterface().notifyRecordAdded(r);

All needed settings are in a JsonObject called params.

3 Likes