ProjectResourceListener usage

I'm trying to create a mechanism to track changes to Vision Windows in a specific project from within a module.

The SDK Programmer's Guide says:

Modules can add a ProjectListener to the ProjectManager in order to be notified when a project is added, removed, or modified. It is important to remember that the listener will be notified for all projects, and that the Project object provided will only be the difference between the last project state and the new one. If the full project is required, for example to resolve full folder paths of resources, you should retrieve it from the ProjectManager using the id provided by the supplied project.

However, the ProjectListener interface appears to only define signatures that provide a string with the name of the project that was added, modified or deleted, and I have not been able to figure out what has changed.

Browsing the JavaDocs, I saw the ProjectResourceListener interface, which seemed to be exactly what I was looking for.

Within my GatewayHook's setup method, I obtained a reference to the project I want to monitor and attempted to add a ProjectResourceListener to it, but the events never seem to fire. I get nothing in the logs and breakpoints never hit with remote debugging.

Can anyone see what I'm doing wrong or point me in a better direction?

Here is the ProjectResourceListener implementation I tried to define and the relevant portion of the code I used to try to hook it up.

public class GatewayHook extends AbstractGatewayModuleHook {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private MyProjectResourceListener myProjectResourceListener = new MyProjectResourceListener();

    @Override
    public void setup(GatewayContext gatewayContext)
    {        
        var myProject = gatewayContext.getProjectManager().getProject("MyProject");
        if (myProject.isPresent()) {
            myProject.get().addProjectResourceListener(myProjectResourceListener);            
        } else {
            logger.warn("My project not found");
        }

    }
}

public class MyProjectResourceListener implements ProjectResourceListener {

    private static Logger logger = LoggerFactory.getLogger(MyProjectResourceListener.class);

    @Override
    public void onBeforeChanges() {
        ProjectResourceListener.super.onBeforeChanges();
    }

    @Override
    public void onAfterChanges() {
        ProjectResourceListener.super.onAfterChanges();
    }

    @Override
    public void manifestChanged(String projectName, List<ChangeOperation.ManifestChangeOperation> operation) {
        ProjectResourceListener.super.manifestChanged(projectName, operation);
    }

    @Override
    public void resourcesCreated(String s, List<ChangeOperation.CreateResourceOperation> list) {
        logger.info("Resources created: " + s);
    }

    @Override
    public void resourcesModified(String s, List<ChangeOperation.ModifyResourceOperation> list) {
        logger.info("Resources modified: " + s);
    }

    @Override
    public void resourcesDeleted(String s, List<ChangeOperation.DeleteResourceOperation> list) {
        logger.info("Resources deleted: " + s);
    }

    @Override
    public ResourceFilter getResourceFilter() {
        return ProjectResourceListener.super.getResourceFilter();
    }
}

I think you hit an unfortunate edge case of the UI. We (exclusively, it appears) use addProjectResourceListener in the designer, where the RuntimeProject instance doesn’t change. It looks like the gateway implementation is different, so the listener isn’t being wired up appropriately.

What I would do instead is create a ProjectLifecycleFactory implementation. Construct it in setup(), then start it and shut it down in the appropriate gateway hook methods. ProjectLifecycleFactory can be overridden to only care about your particular project, and will automatically create ProjectLifecycle instances attached to your project. Those lifecycle instances will get updates as your project(s) change.

Thank you. I was able to create a ProjectLifecyleFactory and get it to return a ProjectLifecycle that lets me know when the resources are updated. I can see the list of created / modified resources now, but I’m not able to tell what has changed on those resources.

Specifically, I’m looking to figure out what changes were made to a Vision window in the project.

When I try to deserialize the window data I get a ClassNotFoundException for FPMIWindow. I tried adding a reference to vision-client but I still get the error. I’m not even sure if this is the right approach.

Windows aren’t stored with any kind of information about what changed.

Even if you could de-serialize a window in the gateway scope, the very best thing you could maybe hope to achieve would be to re-serialize it in the “XML” format you can get by exporting a window in the designer, then assuming you have another prior version of the window to compare it to, run a textual diff, and then basically do nothing because it’s not going to be useful.

1 Like

I hit like on this because it is true. Not because I like it. ):