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:
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:
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??
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>