Make Beans persistable and set properties from a DaemonModule

I’d like to make a bean persistable because when i publish a document i want to set some properties of this bean.

So, i implemented a DaemonModule and catch the publication event, but i’m not able to set and save properties.

The ony documentation i found is this one:

Can anyone provide a simple example of implementation ?

Thanks in advance!

Maybe you’re confusing a daemon module which lives in the CMS/repository app with implementation of an HST component #doAction method to write beans, in the site app.

An example of a daemon module with event listener is at https://documentation.bloomreach.com/library/concepts/workflow/workflow-events.html

HTH
Jeroen

Understood what is the difference between a daemon module and hst component.
I presume that the location where write a bean can be everywhere… or must be only in a hst component?

Read again my goal: i want to write some properties of a bean after the pubblication event.
How would you implement it?

Enzo

Beans are typically in HST, on the site side. On CMS side we normally use JCR API.
Read again my reference, section Implement Publication Post-Processing?

Jeroen

So, this is my daemon implementation. Everything is working less the setProperty function. It doesn’t save any “productList” into the published node.

I’m sure i’m missing something… what? Thanks =)

  public class CategoryPopulationDaemon implements DaemonModule {

    private static final Logger log = LoggerFactory.getLogger(CategoryPopulationDaemon.class);

    public static final String PUBLICATION_INTERACTION = "default:handle:publish";

    private Session session;

    @Override
    public void initialize(final Session session) throws RepositoryException {
        this.session = session;
        HippoEventListenerRegistry.get().register(this);
    }

    @Override
    public void shutdown() {
        HippoEventListenerRegistry.get().unregister(this);
    }

    @Subscribe
    public void handleEvent(final HippoWorkflowEvent event) {
        if (event.success() && PUBLICATION_INTERACTION.equals(event.interaction())) {
            postPublish(event);
        }
    }

    private void postPublish(final HippoWorkflowEvent workflowEvent) {
        try {
            final HippoNode handle = (HippoNode) session.getNodeByIdentifier(workflowEvent.subjectId());
            final Node published = getPublishedVariant(handle);

            if(published != null && published.isNodeType("myproject:QueryBuilder")){

                QueryBuilder queryBuilderBean = new QueryBuilder();
                queryBuilderBean.setNode(published);

                List<String> products = QueryBuilderUtils.getQueryBuilderProducts(queryBuilderBean);
                String[] productList = products.toArray(new String[products.size()]);
                published.setProperty("myproject:products", productList);
            }

        } catch (ItemNotFoundException e) {
            log.warn("Something's wrong because I can't find the handle of the document that was just published");
        } catch (RepositoryException e) {
            log.error("Something's very wrong: unexpected exception while doing simple JCR read operations", e);
        }
    }

    private static Node getPublishedVariant(Node handle) throws RepositoryException {
        for (Node variant : new NodeIterable(handle.getNodes(handle.getName()))) {
            final String state = JcrUtils.getStringProperty(variant, HippoStdNodeType.HIPPOSTD_STATE, null);
            if (HippoStdNodeType.PUBLISHED.equals(state)) {
                return variant;
            }
        }
        return null;
    }

}

Hi Enzo,

There are two problems: minor and major.

The minor issue is you need to call session.save() after setting the property.
The major issue is your event listener is not thread-safe because the JCR session is by design not thread-safe.

Let’s call the session in the initialize() method a system session, given by the system. You should not use that system session when handling events because event handling can be called concurrently in different threads at the same time.

So, the rule of thumb is:

  • Always create a new JCR session (from the given system session) in each event handling process.
  • Make sure to logout the session to avoid session leaks (e.g, finally block).

On how to create a new JCR session from the given system session, please be referred to this example:

Create a new JCR session through #impersonate() using the SYSTEM_CREDENTIALS on the given system session.

Regards,

Woonsan

1 Like

Thanks woonsanko!
Works perfectly. This is my code, if can help anyone:

@Subscribe
public void handleEvent(final HippoWorkflowEvent event) {
    if (event.success() && SAVE_INTERACTION.equals(event.interaction())) {
        postPublish(event);
    }
}

private void postPublish(final HippoWorkflowEvent workflowEvent) {

    Session jcrSession = null;

    try {
        jcrSession = this.session.impersonate(SYSTEM_CREDENTIALS);

        HippoNode handle = (HippoNode) jcrSession.getNodeByIdentifier(workflowEvent.subjectId());
        Node published= getPublishedVariant(handle, HippoStdNodeType.UNPUBLISHED);

        if(published != null){
            String[] productList = ..... 
            published.setProperty(QueryBuilder.QB_PRODUCTS_PROPERTY, productList);

            if (jcrSession.hasPendingChanges()) {
                jcrSession.save();
            }
        }

    } catch (ItemNotFoundException e) {
        log.warn("Something's wrong because I can't find the handle of the document that was just published");
    } catch (RepositoryException e) {
        log.error("Something's very wrong: unexpected exception while doing simple JCR read operations", e);
    }finally {
        if(jcrSession != null){
            jcrSession.logout();
        }
    }
}

Regards,
Enzo