cancel
Showing results for 
Search instead for 
Did you mean: 

Deploying a transaction event listener in a Desktop installation

AlbertGevorgyan
Node Clone

I have created a project that contains an ExtensionFactory subclass annotated as @ServiceProvider that returns a LifecycleAdapter subclass which registers a transaction event listener in its start() method, as shown in this example. The code is below:

@ServiceProvider
public class EventListenerExtensionFactory extends ExtensionFactory<EventListenerExtensionFactory.Dependencies> {

    private final List<TransactionEventListener<?>> listeners;

    public EventListenerExtensionFactory() {
        this(List.of(new MyListener()));
    }

    public EventListenerExtensionFactory(List<TransactionEventListener<?>> listeners) {
        super(ExtensionType.DATABASE, "EVENT_LISTENER_EXT_FACTORY");
        this.listeners = listeners;
    }

    @Override
    public Lifecycle newInstance(ExtensionContext context, Dependencies dependencies) {
        return new EventListenerLifecycleAdapter(dependencies, listeners);
    }

    @RequiredArgsConstructor
    private static class EventListenerLifecycleAdapter extends LifecycleAdapter {

        private final Dependencies dependencies;
        private final List<TransactionEventListener<?>> listeners;

        @Override
        public void start() {
            DatabaseManagementService managementService = dependencies.databaseManagementService();
            listeners.forEach(listener -> managementService.registerTransactionEventListener(
                    DEFAULT_DATABASE_NAME, listener));
            dependencies.log()
                    .getUserLog(EventListenerExtensionFactory.class)
                    .info("Registering transaction event listener for database " + DEFAULT_DATABASE_NAME);
        }
    }

    interface Dependencies {
        DatabaseManagementService databaseManagementService();
        LogService log();
    }
}

It works fine in an integration test:

public AbstractDatabaseTest(TransactionEventListener<?>... listeners) {
        URI uri = Neo4jBuilders.newInProcessBuilder()
                .withExtensionFactories(List.of(new EventListenerExtensionFactory(List.of(listeners))))
                .withDisabledServer()
                .build()
                .boltURI();
        driver = GraphDatabase.driver(uri);
        session = driver.session();
    }

Then I copy the jar file in the plugins directory of my desktop database:

$ cp build/libs/<myproject>.jar /mnt/c/Users/albert.gevorgyan/.Neo4jDesktop/relate-data/dbmss/dbms-7fe3cbdb-11b2-4ca2-81eb-474edbbb3dda/plugins/

I restart the database and even the whole desktop Neo4j program but it doesn't seem to identify the plugin or to initialize the factory: no log messages are found in neo4j.log after the start event, and the transaction events that should be captured by my listener are ignored. Interestingly, a custom function that I have defined in the same jar file actually works - I can call it in the browser. So something must be missing in the extension factory as it doesn't get instantiated.

Is it possible at all to deploy an ExtensionFactory in a Desktop installation and if yes, what am I doing wrong?

P.S. A similar question has been asked about custom plugins: Desktop vs community ? / plugins install - #8 by MuddyBootsCode

1 ACCEPTED SOLUTION

AlbertGevorgyan
Node Clone

It works after I added a provider configuration file to META-INF/services, as explained in https://www.baeldung.com/java-spi. Neo4j finds it then.

View solution in original post

1 REPLY 1

AlbertGevorgyan
Node Clone

It works after I added a provider configuration file to META-INF/services, as explained in https://www.baeldung.com/java-spi. Neo4j finds it then.