Documentation

Creating a Model Listener

Model listeners listen for persistence method calls that signal changes to a specified model (such as update or add methods). Most of the methods model listeners use are called from DXP’s BasePersistenceImpl class. You can define model listeners for out-of-the-box entities (like JournalArticle or AssetEntry), or for your own entities.

To add a model listener, you implement the ModelListener interface.

Here, you’ll learn how to create model listeners:

  1. Examine a Running Model Listener

  2. Identify a Model Class and Event

  3. Declare the Model

  4. Declare the Event

  5. Implement Your Business Logic

  6. Deploy and Test

Examine a Running Model Listener

First, deploy an example model listener for the JournalArticle model on your instance of Liferay DXP:

  1. Start the DXP image.

    docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.1-ga2
    
  2. Download and unzip Acme Model Listener.

    curl https://learn.liferay.com/dxp/latest/en/liferay-internals/extending-liferay/liferay-n4g6.zip -O
    
    unzip liferay-n4g6.zip
    
  3. Build and deploy the example.

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    

    Note

    This command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.

  4. Confirm the deployment in the Docker container console.

    STARTED com.acme.n4g6.impl_1.0.0
    
  5. Verify that the example model listener was added by viewing the added log message. Open your browser to https://localhost:8080 and navigate to the Site menu → Content & DataWeb Content.

    The web content administration page is your interface for creating web content.

    Click the add Add button, then click Basic Web Content to add a new article. Fill out a title and some content; then click Publish. A warning message appears in the console:

    2020-03-17 23:14:56.301 WARN  [http-nio-8080-exec-5][N4G6ModelListener:23] Added journal article 20478.
    

Congratulations! You’ve successfully built and deployed a new model listener that implements ModelListener.

As you can see, Model Listeners listen for an event on a particular model. For this listener, the event is onAfterCreate. When the content is created, the listener “hears” the event, and the action is fired when the event happens.

Now you’ll modify the example to listen for a different event.

Identify a Model Class and Event

Model classes in Liferay DXP are generated by Service Builder. Model interfaces can be found in the -api module of any application. For example, to find the model interface for a Message Boards message, look in the modules/apps/message-boards/message-boards-api project in Liferay DXP’s source code.

The exception to this rule is for core models. If you want to create a Model Listener for a core class such as User, you can find its interface in the portal-kernel folder of Liferay DXP’s source code.

The model listener you’ll create is for a Message Boards message. You’ll trigger a message that prints in the log a report when a message is deleted. For a list of possible events, see the Javadoc for BaseModelListener.

Model Listener Behavior

Model listeners implement the ModelListener interface for specific entities. Model listeners can have code to execute before or after those entities are created, updated, or removed. All of these methods are called from the BasePersistenceImpl class; the code for created or updated entities is called from the update method in BasePersistenceImpl, and the code for removed entities is called from the remove method in BasePersistenceImpl.

Model listeners can also have code to execute before or after other kinds of related entities are added or removed. These methods are called from the _addTableMapping method in TableMapperImpl.

Now you’ll modify the project so it operates on the MBMessage class and the onBeforeRemove event.

Declare the Model

  1. Open the N4G6ModelListener class in your text editor or IDE.

  2. Find the class declaration:

    @Component(service = ModelListener.class)
    public class N4G6ModelListener extends BaseModelListener<JournalArticle> {
    

    When extending BaseModelListener, you define the model class where your listener listens for events (in this example, JournalArticle).

  3. Modify the model class to MBMessage:

    @Component(service = ModelListener.class)
    public class N4G6ModelListener extends BaseModelListener<MBMessage> {
    

    When this model listener is registered, it listens to events for the model defined. The model can be an out-of-the-box entity or a custom entity. Extending the BaseModelListener class gives a default, empty implementation for each of ModelListener’s methods, so your code stays clean and contains overrides for only the events you need.

Declare the Event

Next, override the implementation for the event you want:

  1. Find the onAfterCreate method:

    public void onAfterCreate(JournalArticle journalArticle)
    
  2. Change the method so it overrides onBeforeRemove and passes the MBMessage as a parameter called model:

    public void onBeforeRemove(MBMessage model)
    

Implement Your Business Logic

Triggering a particular action is a typical reason to listen for a particular model event. This example keeps things simple: when a Message Boards message is deleted, we want to report the message’s subject in the logs.

  1. In your new onBeforeRemove method, replace the if statement with this one:

    if (_log.isWarnEnabled()) {
        _log.warn("Warning! Message " + model.getSubject() + " was just removed.");
    }
    
  2. Add the new import for MBMessage to your imports section at the top of the file:

    import com.liferay.message.boards.model.MBMessage;
    

    Remove the unused import for JournalArticle.

  3. Save your new model listener.

Deploy and Test

You can build and deploy the model listener as you did above:

./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)

Test your listener by adding and then deleting a message boards message:

  1. Go to Product MenuContent & DataMessage Boards.

  2. Click the add Add button, type a Subject and a Body, and click Publish.

  3. Click Message Boards from the menu again to see your message. Click the Action Action button and choose Move to Recycle Bin. Notice that you don’t see your message in the logs yet because the message has only been recycled.

  4. Click Recycle Bin from the Product Menu, and you’ll see your message.

  5. Click the Action Action button and select Delete. Confirm the deletion.

  6. Check your log. Your message appears:

    2020-04-17 21:10:31.080 WARN  [http-nio-8080-exec-5][N4G6ModelListener:19] Warning! Message This is a Test Message was just removed.
    

Conclusion

Congratulations! You now know how to implement the ModelListener interface, and have added a new model listener to Liferay DXP.