Juan Melo
Juan Melo

Reputation: 330

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

Upvotes: 1

Views: 129

Answers (2)

Eric Long
Eric Long

Reputation: 926

If you use sym_extension table for your extension code, then there is nothing more to do. The advantage is your extension becomes part of the configuration. You deployed SymmetricDS to Tomcat, and it looks like its classloader hierarchy is preventing compilation. If you use the standalone SymmetricDS server, it will work.

If you compile your code to a JAR, you can put a Spring XML file into the JAR named symmetric-extensions.xml in the "conf" sub-directory that will register your extension as a Spring bean. Or you can edit the file conf/symmetric-extensions.xml that is part of the SymmetricDS installation. I prefer putting the file in the JAR so it is self-contained.

Upvotes: 0

Boris Pavlović
Boris Pavlović

Reputation: 64640

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>

Upvotes: 0

Related Questions