Search code examples
javaspring-bootsymmetricds

ClientSymmetricEngine 3.12.7 - Unable to compile IAcknowledgeEventListener Java extension point


Having a hell of a time making SymmetricDS java extension points work.

This is what I've tried:

1. created this class:


package com.gourmet.listener;

import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.ext.ISymmetricEngineAware;
import org.jumpmind.symmetric.model.BatchAck;
import org.jumpmind.symmetric.transport.IAcknowledgeEventListener;

public class AcknowledgeListener implements IAcknowledgeEventListener, ISymmetricEngineAware {
    ISymmetricEngine _engine;


    @Override
    public void onAcknowledgeEvent(BatchAck batchInfo) {
        if (!batchInfo.isOk()) {
            System.out.println("bachInfo is not OK " + batchInfo);
            return;
        }
        System.out.println("received event!!!!!!! {}" + batchInfo);
    }

    @Override
    public void setSymmetricEngine(ISymmetricEngine engine) {
        _engine = engine;

    }
}

2. Placed `Manifest.txt in the same package location as AcknowledgeListener.java

Class-Path: symmetric-core-3.12.7.jar symmetric-util-3.12.7.jar

3. Generated jar file with AcknowledgeListener and placed it in WEB-INF/lib

cd /gourmet3/mobile-webpage/src/main/java

javac -cp ".:/gourmet3/mobile-webpage/target/gourmet/WEB-INF/lib/symmetric-util-3.12.7.jar:/gourmet3/mobile-webpage/target/gourmet/WEB-INF/lib/symmetric-core-3.12.7.jar" com/gourmet/listener/AcknowledgeListener.java

jar cfm com/gourmet/listener/AcknowledgeListener.jar com/gourmet/listener/Manifest.txt com/gourmet/listener/*.class

mv com/gourmet/listener/AcknowledgeListener.jar /gourmet3/mobile-webpage/src/main/webapp/WEB-INF/lib

rm com/gourmet/listener/AcknowledgeListener.*

This is the result:

enter image description here

MANIFEST.MF:

Manifest-Version: 1.0
Class-Path: symmetric-core-3.12.7.jar symmetric-util-3.12.7.jar
Created-By: 1.8.0_272 (Azul Systems, Inc.)

As SymmetricDS 3.2 documentation states, I created conf/symmetric-extensions.xml so spring finds the bean.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="acknowledgeListener" class="com.gourmet.listener.AcknowledgeListener"/>
</beans>

Created the sym_extension entry SQL in the server and client databases

insert into sym_extension (extension_id, extension_type, interface_name, node_group_id, enabled, extension_order,
                           extension_text, create_time, last_update_by, last_update_time)
values ('acknowledge batch', 'java', 'org.jumpmind.symmetric.transport.IAcknowledgeEventListener','sucursal', 1, 1,
        '
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.ext.ISymmetricEngineAware;
import org.jumpmind.symmetric.model.BatchAck;
import org.jumpmind.symmetric.transport.IAcknowledgeEventListener;

public class AcknowledgeListener implements IAcknowledgeEventListener, ISymmetricEngineAware {
    ISymmetricEngine _engine;


    @Override
    public void onAcknowledgeEvent(BatchAck batchInfo) {
        if (!batchInfo.isOk()) {
            System.out.println("bachInfo is not OK " + batchInfo);
            return;
        }
        System.out.println("received event!!!!!!! {}" + batchInfo);
    }

    @Override
    public void setSymmetricEngine(ISymmetricEngine engine) {
        _engine = engine;

    }
}
', current_timestamp, 'some user', current_timestamp);

And when I try to run the Sym Client, i always get an exception.

20 Mar 2021 20:17:10 ERROR [org.jumpmind.symmetric.service.impl.ExtensionService] - <Error while compiling Java extension acknowledge batch>
org.jumpmind.util.SimpleClassCompilerException: Compilation of 'AcknowledgeListener' failed.
AcknowledgeListener at line 2, column 30: package org.jumpmind.symmetric does not exist
AcknowledgeListener at line 3, column 34: package org.jumpmind.symmetric.ext does not exist
AcknowledgeListener at line 4, column 36: package org.jumpmind.symmetric.model does not exist
AcknowledgeListener at line 5, column 40: package org.jumpmind.symmetric.transport does not exist
AcknowledgeListener at line 7, column 46: cannot find symbol
  symbol: class IAcknowledgeEventListener
AcknowledgeListener at line 7, column 73: cannot find symbol
  symbol: class ISymmetricEngineAware
AcknowledgeListener at line 8, column 5: cannot find symbol
  symbol:   class ISymmetricEngine
  location: class SimpleClassCompiler0
AcknowledgeListener at line 12, column 36: cannot find symbol
  symbol:   class BatchAck
  location: class SimpleClassCompiler0
AcknowledgeListener at line 21, column 36: cannot find symbol
  symbol:   class ISymmetricEngine
  location: class SimpleClassCompiler0
AcknowledgeListener at line 11, column 5: method does not override or implement a method from a supertype
AcknowledgeListener at line 20, column 5: method does not override or implement a method from a supertype

    at org.jumpmind.util.SimpleClassCompiler.getCompiledClass(SimpleClassCompiler.java:119)
    at org.jumpmind.symmetric.service.impl.ExtensionService.registerExtension(ExtensionService.java:110)
    at org.jumpmind.symmetric.service.impl.ExtensionService.refresh(ExtensionService.java:101)
    at org.jumpmind.symmetric.service.impl.ClientExtensionService.refresh(ClientExtensionService.java:46)
    at org.jumpmind.symmetric.AbstractSymmetricEngine.init(AbstractSymmetricEngine.java:348)
    at org.jumpmind.symmetric.ClientSymmetricEngine.init(ClientSymmetricEngine.java:205)
    at org.jumpmind.symmetric.ClientSymmetricEngine.<init>(ClientSymmetricEngine.java:148)
    at org.jumpmind.symmetric.ClientSymmetricEngine.<init>(ClientSymmetricEngine.java:152)
    at com.gourmet.symmetricds.SymDSStarter.postConstruct(SymDSStarter.java:54)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:346)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:299)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:132)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:394)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1448)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4705)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5171)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:743)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:719)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1663)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:286)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:482)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:431)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:286)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Notes:

  1. I've tried with & without package com.gourmet.listener; path in the SQL script.
  2. I removed the java and compiled .class files from com.gourmet.listener package.
  3. symmetric-core-3.12.7.jar, symmetric-util-3.12.7.jar and AcknowledgeListener.jar exist into WEB-INF/lib.

So, not sure what am I missing?

HAAALP!

EDIT

This is so weird, I commented out the script which inserts into sym_extension and deleted all table rows (from server and client DBs), .jar file was left in WEB-INF\lib and the java file in the package where I compiled it, and suddenly it worked and I'm even able to debug. Why is symmetricDS even calling it when there's no rows in the sym_extension table??

enter image description here


Solution

  • The class that's extending basic functionality should not be placed in a custom package. Drop the line:

    package com.gourmet.listener;
    

    Then add the file conf/symmetric-extensions.xml with this content:

    <?xml version="1.0" encoding="UTF-8"?>
    <!--
    
        Licensed to JumpMind Inc under one or more contributor
        license agreements.  See the NOTICE file distributed
        with this work for additional information regarding
        copyright ownership.  JumpMind Inc licenses this file
        to you under the GNU General Public License, version 3.0 (GPLv3)
        (the "License"); you may not use this file except in compliance
        with the License.
    
        You should have received a copy of the GNU General Public License,
        version 3.0 (GPLv3) along with this library; if not, see
        <http://www.gnu.org/licenses/>.
    
        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
    
    -->
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
           default-lazy-init="true">
    
        <bean id="acknowledgeListener" class="AcknowledgeListener" />
    </beans>