Legacy Knowledge Base
Published Sep. 10, 2025

ConfigurationModelListener runs in both nodes

Written By

Sorin Pop

How To articles are not official guidelines or officially supported documentation. They are community-contributed content and may not always reflect the latest updates to Liferay DXP. We welcome your feedback to improve How To articles!

While we make every effort to ensure this Knowledge Base is accurate, it may not always reflect the most recent updates or official guidelines.We appreciate your understanding and encourage you to reach out with any feedback or concerns.

Legacy Article

You are viewing an article from our legacy "FastTrack" publication program, made available for informational purposes. Articles in this program were published without a requirement for independent editing or verification and are provided"as is" without guarantee.

Before using any information from this article, independently verify its suitability for your situation and project.

Issue

  • I developed a module to track system configuration changes using a model listener that implements ConfigurationModelListener. While everything is functioning correctly, there's an issue where this module executes on both nodes. Typically, when a request occurs on node 1, the corresponding action takes place on node 1. However, in this scenario, it runs on both node 1 and node 2.

    Steps to reproduce:
    1. Set up a cluster of 2 nodes.
    2. In one of the nodes, go to Control Panel > System Settings > Security > Audit, uncheck the Enabled checkbox and save. (just to do an initial saving of this setting)
    3. Deploy the attached PoC module on both nodes. (Liferay-configlistener-clusterIssue.zip)
    4. In one of the nodes, enable that setting again and watch the logs of both nodes, look for a log starting with "oldauditEnabled:::".
    Result: it is printed in both nodes, indicating that the call occurs in both nodes.
    Expected: The expectation is that, upon calling the deployable JAR, the log should only be printed in one node of a clustered server.

Environment

  • 7.4

Resolution

  • Our team is working on redesigning the ConfigurationModelListener, even removing some methods that should have never have been added to the API. The current design was only intended to validate configurations, not to be executed across the cluster. Since this redesign can take time, we are suggesting an alternative to what you are trying to achieve, using ConfigurationModelListener, something like this:
     
    import org.osgi.service.cm.ConfigurationEvent; 
    import org.osgi.service.cm.ConfigurationListener; 
    import org.osgi.service.component.annotations.Component; 

    @Component(service = ConfigurationListener.class) 
    public class TracingConfigurationListener implements ConfigurationListener { 
    @Override 
    public void configurationEvent(ConfigurationEvent configurationEvent) { 
    System.out.println("############Configuration Event : " + configurationEvent.getType() + " for " + configurationEvent.getPid()); 

    }
     
     
    This solution is based on creating a ConfigurationListener instead of a ConfigurationModelListener, and listen to a configuration event. You should only implement the configurationEvent method.
     
    In the PoC provided earlier the class GenericConfigurationListener was created and  method onBeforeSave was implemented. With our suggestion you would need to:
    1. Adapt the class to implement ConfigurationListener instead of ConfigurationModelListener.
    2. Use the logic of onBeforeSave in the new needed to implement method configurationEvent
    3. Check that the configurationEvent.getPid() is equal to the configuration you want to listen (com.liferay.portal.security.audit.configuration.AuditConfiguration)
    4. You should only apply the logic for the kind of configurationEvent you want (ConfigurationEvent.CM_UPDATED, ConfigurationEvent.CM_DELETED)
     
    To clarify things you can take a look, for example, to our class https://github.com/liferay/liferay-portal/blob/88cf28caf54d71b332b6fd1bc2bb07ed29b847a7/modules/apps/portal-security/portal-security-ldap-impl/src/main/java/com/liferay/portal/security/ldap/internal/configuration/LDAPConfigurationListener.java that also implements ConfigurationListener.
     
    Also, if you need that your code is executed on each node you can extract them to a separate class and use either the Clusterable annotation or the ClusterExecutorUtil as explained here: https://help.liferay.com/hc/en-us/articles/360018154832-Liferay-s-Clustering-API
     
    To summarize:
    • The ConfigurationModelListener logic is going to be changed and most likely it will not be executed in the cluster.
    • If you want to listen for configuration changes you can use your current approach (taking into account that it is going to be redesigned) or follow our approach described above.
    • Once you have listened to the configuration change you can execute whatever code you want with @Clusterable annotation or ClusterExecutorUtil
     

Additional Information

Did this article resolve your issue ?

Legacy Knowledge Base