Task comment create history event

Hi!

I see that there is nothing like HistoricCommentCreatedEvent in history log implementation. I need to notify my custom history backend that task or process instance comment was created (and pass that information together with its content and author).

My only bet currently is to provide custom rest endpoint for adding comments, where my custom backend would be notified.
Do any of you have better idea what could be done to provide this functionality?

Thanks in advance,
Adam

Hi Adam,

Your findings that comments do not go through the HistoryEventHandler are correct. In order to hook into comment creation, you could subclass org.camunda.bpm.engine.impl.persistence.entity.CommentManager and override the appropriate methods. Then create a process engine plugin that registers a session factory for your subclass with the process engine. See engine configuration setter #setCustomSessionFactories, the method ProcessEngineConfigurationImpl#initSessionFactories and the class org.camunda.bpm.engine.impl.persistence.GenericManagerFactory.GenericManagerFactory.

Cheers,
Thorben

1 Like

Hello,

I have the same issue here and I tried your solution @thorben but Camunda is still calling the original CommentManager. I saw in the class CommandContext the following method:

  public CommentManager getCommentManager() {
    return getSession(CommentManager.class);
  }

It always return CommentManager class.

Should I create a custom CommandContext class?

Tks.

Hi @denisgmarques ,

you should not need a subclass of CommandContext. Could you show us how you registered your custom CommentManager implementation?

To make it hopefully clearer already, these should be your steps:

  1. Subclass CommentManager
  2. Subclass SessionFactory to provide your custom CommentManager. You could rely on the generic implementation as @thorben pointed out called GenericManagerFactory.
  3. Write a ProcessEnginePlugin that adds your custom SessionFactory on preInit. It is important that it is defined before the init process starts.

Then, you should be good to go and getCommentManager should create your implementation of the CommentManager.

If you already did these steps, please share relevant snippets and will have a look into it together.

Kind regards
Adagatiya

Hello,

Here it is:

public class CustomCommentManager extends CommentManager {

	@Override
	public void insert(DbEntity dbEntity) {
		super.insert(dbEntity);

		log.info("*********************** SEND MAIL **************************");
	}

}
public class CommentManagerPlugin extends AbstractProcessEnginePlugin {

	@Override
	public void preInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
		// Custom Comment Manager
		List<SessionFactory> customSessionFactories = new ArrayList<>();
		customSessionFactories.add(new GenericManagerFactory(CustomCommentManager.class));
		processEngineConfiguration.setCustomSessionFactories(customSessionFactories);
	}

}
@Configuration
public class ProcessEnginePluginsConfiguration {
	@Bean
	@Order(Ordering.DEFAULT_ORDER + 1)
	public static ProcessEnginePlugin registerCommentManagerPlugin() {
		return new CommentManagerPlugin();
	}
}

Camunda will register my custom CommentManager here:

public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfiguration {
...
  protected void initSessionFactories() {
    ...
    if (customSessionFactories != null) {
      for (SessionFactory sessionFactory : customSessionFactories) {
        addSessionFactory(sessionFactory);
      }
    }
}
...
}

But this does not work because in AddCommentCmd.java Camunda will get CommentManager this way:

public class AddCommentCmd implements Command<Comment>, Serializable {
   ...
  public Comment execute(CommandContext commandContext) {
   ...
    commandContext
      .getCommentManager()
      .insert(comment);
   ...
   }
}

And CommandContext.java will return the original CommentManager:

public class CommandContext {
   ...
  public CommentManager getCommentManager() {
    return getSession(CommentManager.class); // IT WILL NOT RETURN MY CUSTOM CLASS
  }
  ...
}

Denis

Hi @denisgmarques ,

I spotted the problem in your SessionFactory configuration. By default the GenericManagerFactory uses the specific subclass of your implementation as session type, but what you want is to overwrite CommentManager with CustomCommentManager. In order to achieve this, you could use a factory as follows:

public class CustomManagerFactory<T extends Session> extends GenericManagerFactory {

    private final Class<T> sessionType;

    public CustomManagerFactory(Class<T> sessionType, Class<? extends T> implementation) {
        super(implementation);
        this.sessionType = sessionType;
    }

    @Override
    public Class<?> getSessionType() {
        return sessionType;
    }
}

Sidenote:
It is good practise to not override the exisiting custom session factories:

public class CommentManagerPlugin extends AbstractProcessEnginePlugin {

	@Override
	public void preInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
		// Custom Comment Manager
		List<SessionFactory> customSessionFactories = processEngineConfiguration.getCustomSessionFactories();
		customSessionFactories.add(new CustomManagerFactory<>(CommentManager.class, CustomCommentManager.class));
		processEngineConfiguration.setCustomSessionFactories(customSessionFactories);
	}

}

Kind regards
Adagatiya

1 Like