问题描述
在使 SymmetricDS java 扩展点工作时费了一番功夫。
这是我试过的:
1.创建了这个类:
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.将 `Manifest.txt 放置在与 AckNowledgeListener.java 相同的包位置
Class-Path: symmetric-core-3.12.7.jar symmetric-util-3.12.7.jar
3.用AckNowledgeListener生成jar文件放在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.*
结果如下:
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.)
正如 SymmetricDS 3.2 documentation 所述,我创建了 conf/symmetric-extensions.xml 以便 spring 找到 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>
在服务器和客户端数据库中创建了 sym_extension 条目 sql
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,'
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);
当我尝试运行 Sym 客户端时,我总是遇到异常。
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)
注意事项:
- 我试过在 sql 脚本中使用 & 不使用 package com.gourmet.listener; 路径。
- 我从 com.gourmet.listener 包中删除了 java 和编译的 .class 文件。
- symmetric-core-3.12.7.jar、symmetric-util-3.12.7.jar 和 AckNowledgeListener.jar 存在于 WEB-INF/lib。
所以,不确定我错过了什么?
HAAALP!
编辑
这太奇怪了,我注释掉了插入 sym_extension 并删除了所有表行(来自服务器和客户端数据库)的脚本,.jar 文件留在了 WEB-INF\lib 中,而我所在的包中的 java 文件编译它,突然它起作用了,我什至能够调试。当 sym_extension 表中没有行时,为什么 symmetricDS 甚至调用它?
解决方法
扩展基本功能的类不应放在自定义包中。删除该行:
package com.gourmet.listener;
然后添加具有以下内容的文件 conf/symmetric-extensions.xml
:
<?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>
,
如果您使用 sym_extension 表作为您的扩展代码,那么就没有什么可做的了。优点是您的扩展成为配置的一部分。您将 SymmetricDS 部署到 Tomcat,看起来它的类加载器层次结构正在阻止编译。如果您使用独立的 SymmetricDS 服务器,它会工作。
如果您将代码编译为 JAR,则可以将 Spring XML 文件放入名为 symmetric-extensions.xml 的 JAR 中,该 JAR 位于“conf”子目录中,该 JAR 会将您的扩展注册为 Spring bean。或者您可以编辑文件 conf/symmetric-extensions.xml,它是 SymmetricDS 安装的一部分。我更喜欢将文件放在 JAR 中,这样它是独立的。