http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridge.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridge.java 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridge.java
new file mode 100644
index 0000000..d506d6c
--- /dev/null
+++ b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridge.java
@@ -0,0 +1,308 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.util.Base64Codec;
+import org.apache.cayenne.util.Util;
+import org.jivesoftware.smack.GroupChat;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.SSLXMPPConnection;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * An EventBridge implementation based on XMPP protocol and Smack XMPP client 
library.
+ * What's good about XMPP (Extensible Messaging and Presence Protocol, an IETF 
standard
+ * protocol that grew up from Jabber IM) is that generally it has fewer or no 
deployment
+ * limitations (unlike JMS and JGroups that are generally a good solution for 
local
+ * controlled networks). Also it provides lots of additional information for 
free, such as
+ * presence, and much more.
+ * <p>
+ * This implementation is based on Smack XMPP client library from JiveSoftware.
+ * </p>
+ * 
+ * @since 1.2
+ */
+public class XMPPBridge extends EventBridge {
+
+    public static final String XMPP_HOST_PROPERTY = 
"cayenne.XMPPBridge.xmppHost";
+
+    /**
+     * An optional property, port 5222 is used as default XMPP port.
+     */
+    public static final String XMPP_PORT_PROPERTY = 
"cayenne.XMPPBridge.xmppPort";
+
+    /**
+     * An optional property, "conference" is used as default chat service.
+     */
+    public static final String XMPP_CHAT_SERVICE_PROPERTY = 
"cayenne.XMPPBridge.xmppChatService";
+
+    public static final String XMPP_SECURE_CONNECTION_PROPERTY = 
"cayenne.XMPPBridge.xmppSecure";
+    public static final String XMPP_LOGIN_PROPERTY = 
"cayenne.XMPPBridge.xmppLogin";
+    public static final String XMPP_PASSWORD_PROPERTY = 
"cayenne.XMPPBridge.xmppPassword";
+
+    static final String DEFAULT_CHAT_SERVICE = "conference";
+    static final int DEFAULT_XMPP_PORT = 5222;
+    static final int DEFAULT_XMPP_SECURE_PORT = 5223;
+
+    protected boolean secureConnection;
+    protected String loginId;
+    protected String password;
+    protected String xmppHost;
+    protected int xmppPort;
+    protected String chatService;
+    protected String sessionHandle;
+
+    protected XMPPConnection connection;
+    protected GroupChat groupChat;
+    protected boolean connected;
+
+    /**
+     * Creates an XMPPBridge. External subject will be used as the chat group 
name.
+     */
+    public XMPPBridge(EventSubject localSubject, String externalSubject) {
+        this(Collections.singleton(localSubject), externalSubject);
+    }
+
+    /**
+     * Creates an XMPPBridge. External subject will be used as the chat group 
name.
+     */
+    public XMPPBridge(Collection<EventSubject> localSubjects, String 
externalSubject) {
+        super(localSubjects, externalSubject);
+
+        // generate a unique session handle... users can override it to use a 
specific
+        // handle...
+        this.sessionHandle = "cayenne-xmpp-" + System.currentTimeMillis();
+    }
+
+    public XMPPBridge(Collection<EventSubject> localSubjects, String 
externalSubject, Map<String, String> properties) {
+        this(localSubjects, externalSubject);
+
+        this.chatService = properties.get(XMPP_CHAT_SERVICE_PROPERTY);
+        this.xmppHost = properties.get(XMPP_HOST_PROPERTY);
+
+        this.loginId = properties.get(XMPP_LOGIN_PROPERTY);
+        this.password = properties.get(XMPP_PASSWORD_PROPERTY);
+
+        String secureConnectionString = 
properties.get(XMPP_SECURE_CONNECTION_PROPERTY);
+        secureConnection = "true".equalsIgnoreCase(secureConnectionString);
+
+        String portString = properties.get(XMPP_PORT_PROPERTY);
+        if (portString != null) {
+            try {
+                this.xmppPort = Integer.parseInt(portString);
+            } catch (NumberFormatException e) {
+                throw new CayenneRuntimeException("Invalid port: %s", 
portString);
+            }
+        }
+    }
+
+    public String getXmppHost() {
+        return xmppHost;
+    }
+
+    public void setXmppHost(String xmppHost) {
+        this.xmppHost = xmppHost;
+    }
+
+    public int getXmppPort() {
+        return xmppPort;
+    }
+
+    public void setXmppPort(int xmppPort) {
+        this.xmppPort = xmppPort;
+    }
+
+    public String getLoginId() {
+        return loginId;
+    }
+
+    public void setLoginId(String loginId) {
+        this.loginId = loginId;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isSecureConnection() {
+        return secureConnection;
+    }
+
+    public void setSecureConnection(boolean secureConnection) {
+        this.secureConnection = secureConnection;
+    }
+
+    public String getChatService() {
+        return chatService;
+    }
+
+    public void setChatService(String chatService) {
+        this.chatService = chatService;
+    }
+
+    public String getSessionHandle() {
+        return sessionHandle;
+    }
+
+    public void setSessionHandle(String sessionHandle) {
+        this.sessionHandle = sessionHandle;
+    }
+
+    @Override
+    protected void startupExternal() throws Exception {
+
+        // validate settings
+        if (xmppHost == null) {
+            throw new CayenneRuntimeException("Null 'xmppHost', can't start 
XMPPBridge");
+        }
+
+        // shutdown old bridge
+        if (connected) {
+            shutdownExternal();
+        }
+
+        try {
+            // connect and log in to chat
+            if (secureConnection) {
+                int port = xmppPort > 0 ? xmppPort : DEFAULT_XMPP_SECURE_PORT;
+                this.connection = new SSLXMPPConnection(xmppHost, port);
+            } else {
+                int port = xmppPort > 0 ? xmppPort : DEFAULT_XMPP_PORT;
+                this.connection = new XMPPConnection(xmppHost, port);
+            }
+
+            if (loginId != null) {
+                // it is important to provide a (pseudo) globally unique 
string as the
+                // third argument ("sessionHandle" is such string); without it 
same
+                // loginId can not be reused from the same machine.
+                connection.login(loginId, password, sessionHandle);
+            } else {
+                connection.loginAnonymously();
+            }
+        } catch (XMPPException e) {
+            throw new CayenneRuntimeException("Error connecting to XMPP 
Server: %s", e.getLocalizedMessage());
+        }
+
+        String service = chatService != null ? chatService : 
DEFAULT_CHAT_SERVICE;
+        try {
+            groupChat = connection.createGroupChat(externalSubject + '@' + 
service + "." + connection.getHost());
+            groupChat.join(sessionHandle);
+            groupChat.addMessageListener(new XMPPListener());
+        } catch (XMPPException e) {
+            throw new CayenneRuntimeException("Error setting up a group chat: 
%s", e.getLocalizedMessage());
+        }
+
+        this.connected = true;
+    }
+
+    @Override
+    protected void shutdownExternal() throws Exception {
+        if (groupChat != null) {
+            groupChat.leave();
+            groupChat = null;
+        }
+
+        if (connection != null) {
+            connection.close();
+            connection = null;
+        }
+
+        connected = false;
+    }
+
+    @Override
+    protected void sendExternalEvent(CayenneEvent localEvent) throws Exception 
{
+
+        Message message = groupChat.createMessage();
+        message.setBody(serializeToString(localEvent));
+
+        // set thread to our session handle to be able to discard messages 
from self
+        message.setThread(sessionHandle);
+
+        groupChat.sendMessage(message);
+    }
+
+    class XMPPListener implements PacketListener {
+
+        public void processPacket(Packet packet) {
+
+            if (packet instanceof Message) {
+                Message message = (Message) packet;
+
+                // filter our own messages
+                if (sessionHandle.equals(message.getThread())) {
+                    String payload = message.getBody();
+                    try {
+                        Object event = deserializeFromString(payload);
+                        if (event instanceof CayenneEvent) {
+                            onExternalEvent((CayenneEvent) event);
+                        }
+                    } catch (Exception ex) {
+                        // ignore for now... need to add logging.
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Decodes the String (assuming it is using Base64 encoding), and then 
deserializes
+     * object from the byte array.
+     */
+    static Object deserializeFromString(String string) throws Exception {
+        if (Util.isEmptyString(string)) {
+            return null;
+        }
+
+        byte[] bytes = Base64Codec.decodeBase64(string.getBytes());
+        ObjectInputStream in = new ObjectInputStream(new 
ByteArrayInputStream(bytes));
+        Object object = in.readObject();
+        in.close();
+        return object;
+    }
+
+    /**
+     * Serializes object and then encodes it using Base64 encoding.
+     */
+    static String serializeToString(Object object) throws Exception {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(bytes);
+        out.writeObject(object);
+        out.close();
+
+        return new String(Base64Codec.encodeBase64(bytes.toByteArray()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
new file mode 100644
index 0000000..7934752
--- /dev/null
+++ b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
@@ -0,0 +1,41 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A factory of XMPPBridge. Note that to deploy an XMPPBridge, you need to have
+ * <em>smack.jar</em> library in the runtime.
+ * 
+ * @since 1.2
+ */
+public class XMPPBridgeFactory implements EventBridgeFactory {
+
+    @Override
+    public EventBridge createEventBridge(
+            Collection<EventSubject> localSubjects,
+            String externalSubject,
+            Map<String, String> properties) {
+        return new XMPPBridge(localSubjects, externalSubject, properties);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java
new file mode 100644
index 0000000..38c9874
--- /dev/null
+++ 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java
@@ -0,0 +1,50 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.access.DataRowStore;
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class XMPPBridgeProvider implements Provider<EventBridge> {
+
+    @Inject
+    protected DataDomain dataDomain;
+
+    @Inject(XMPPModule.XMPP_BRIDGE_PROPERTIES_MAP)
+    Map<String, String> properties;
+
+    @Override
+    public EventBridge get() throws DIRuntimeException {
+        EventSubject snapshotEventSubject = 
EventSubject.getSubject(DataRowStore.class.getClass(), dataDomain.getName());
+
+        return new XMPPBridge(
+                Collections.singleton(snapshotEventSubject),
+                EventBridge.convertToExternalSubject(snapshotEventSubject),
+                properties);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPModule.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPModule.java 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPModule.java
new file mode 100644
index 0000000..83c8f0a
--- /dev/null
+++ b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPModule.java
@@ -0,0 +1,71 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.MapBuilder;
+import org.apache.cayenne.di.Module;
+
+/**
+ * @since 4.0
+ */
+public class XMPPModule implements Module {
+
+    /**
+     * A DI container key for the Map&lt;String, String&gt; storing
+     * {@link org.apache.cayenne.event.XMPPBridge} properties
+     *
+     * @since 4.0
+     */
+    public static final String XMPP_BRIDGE_PROPERTIES_MAP = 
"cayenne.server.xmpp_bridge";
+
+    public static void contributeHost(Binder binder, String host) {
+        contributeProperties(binder).put(XMPPBridge.XMPP_HOST_PROPERTY, host);
+    }
+
+    public static void contributePort(Binder binder, int port) {
+        contributeProperties(binder).put(XMPPBridge.XMPP_PORT_PROPERTY, 
Integer.toString(port));
+    }
+
+    public static void contributeLogin(Binder binder, String login, String 
password) {
+        contributeProperties(binder).put(XMPPBridge.XMPP_LOGIN_PROPERTY, 
login);
+        contributeProperties(binder).put(XMPPBridge.XMPP_PASSWORD_PROPERTY, 
password);
+    }
+
+    public static void contributeChatService(Binder binder, String 
chatService) {
+        
contributeProperties(binder).put(XMPPBridge.XMPP_CHAT_SERVICE_PROPERTY, 
chatService);
+    }
+
+    public static void contributeSecureConnection(Binder binder, boolean 
secure) {
+        
contributeProperties(binder).put(XMPPBridge.XMPP_SECURE_CONNECTION_PROPERTY, 
Boolean.toString(secure));
+    }
+
+    private static MapBuilder<String> contributeProperties(Binder binder) {
+        return binder.bindMap(String.class, XMPP_BRIDGE_PROPERTIES_MAP);
+    }
+
+    @Override
+    public void configure(Binder binder) {
+        // init properties' defaults
+        contributeChatService(binder, XMPPBridge.DEFAULT_CHAT_SERVICE);
+
+        binder.bind(EventBridge.class).toProvider(XMPPBridgeProvider.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPServerModuleProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPServerModuleProvider.java
 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPServerModuleProvider.java
new file mode 100644
index 0000000..e8cf3da
--- /dev/null
+++ 
b/cayenne-xmpp/src/main/java/org/apache/cayenne/event/XMPPServerModuleProvider.java
@@ -0,0 +1,50 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
+import org.apache.cayenne.configuration.server.ServerModule;
+import org.apache.cayenne.di.Module;
+
+/**
+ * @since 4.0
+ */
+public class XMPPServerModuleProvider implements CayenneServerModuleProvider {
+
+    @Override
+    public Module module() {
+        return new XMPPModule();
+    }
+
+    @Override
+    public Class<? extends Module> moduleType() {
+        return XMPPModule.class;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Collection<Class<? extends Module>> overrides() {
+        Collection modules = Collections.singletonList(ServerModule.class);
+        return modules;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
 
b/cayenne-xmpp/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
new file mode 100644
index 0000000..00bce56
--- /dev/null
+++ 
b/cayenne-xmpp/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
@@ -0,0 +1,20 @@
+##################################################################
+#   Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  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.
+##################################################################
+
+org.apache.cayenne.event.XMPPServerModuleProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/test/java/org/apache/cayenne/event/CayenneXMPPModuleProviderTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/test/java/org/apache/cayenne/event/CayenneXMPPModuleProviderTest.java
 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/CayenneXMPPModuleProviderTest.java
new file mode 100644
index 0000000..0826f7c
--- /dev/null
+++ 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/CayenneXMPPModuleProviderTest.java
@@ -0,0 +1,36 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
+import org.apache.cayenne.unit.util.ModuleProviderChecker;
+import org.junit.Test;
+
+/**
+ * @since 4.0
+ */
+public class CayenneXMPPModuleProviderTest {
+
+    @Test
+    public void testAutoLoadable() {
+        
ModuleProviderChecker.testProviderPresent(XMPPServerModuleProvider.class, 
CayenneServerModuleProvider.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeFactoryTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeFactoryTest.java
 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeFactoryTest.java
new file mode 100644
index 0000000..b5aa80a
--- /dev/null
+++ 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeFactoryTest.java
@@ -0,0 +1,72 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.junit.Test;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class XMPPBridgeFactoryTest {
+
+    protected Collection<EventSubject> subjects = Collections.singleton(new 
EventSubject("test"));
+    protected String externalSubject = "subject";
+
+    @Test
+    public void testCreateEventBridge() {
+        EventBridge bridge = new XMPPBridgeFactory().createEventBridge(
+                subjects,
+                externalSubject,
+                Collections.<String, String>emptyMap());
+
+        assertTrue(bridge instanceof XMPPBridge);
+        assertEquals(subjects, bridge.getLocalSubjects());
+        assertEquals(externalSubject, bridge.getExternalSubject());
+    }
+
+    @Test
+    public void testUseMapPropertiesSetter() throws Exception {
+        XMPPBridgeFactory bridgeFactory = new XMPPBridgeFactory();
+        Map<String, String> properties = new HashMap<>();
+
+        properties.put(XMPPBridge.XMPP_HOST_PROPERTY, 
XMPPBridgeProviderTest.HOST_TEST);
+        properties.put(XMPPBridge.XMPP_CHAT_SERVICE_PROPERTY, 
XMPPBridgeProviderTest.CHAT_SERVICE_TEST);
+        properties.put(XMPPBridge.XMPP_LOGIN_PROPERTY, 
XMPPBridgeProviderTest.LOGIN_TEST);
+        properties.put(XMPPBridge.XMPP_PASSWORD_PROPERTY, 
XMPPBridgeProviderTest.PASSWORD_TEST);
+        properties.put(XMPPBridge.XMPP_SECURE_CONNECTION_PROPERTY, 
String.valueOf(XMPPBridgeProviderTest.SECURE_CONNECTION_TEST));
+        properties.put(XMPPBridge.XMPP_PORT_PROPERTY, 
String.valueOf(XMPPBridgeProviderTest.PORT_TEST));
+
+        XMPPBridge bridge = (XMPPBridge) 
bridgeFactory.createEventBridge(subjects,
+                externalSubject,
+                properties);
+
+        assertEquals(bridge.getXmppHost(), XMPPBridgeProviderTest.HOST_TEST);
+        assertEquals(bridge.getChatService(), 
XMPPBridgeProviderTest.CHAT_SERVICE_TEST);
+        assertEquals(bridge.getLoginId(), XMPPBridgeProviderTest.LOGIN_TEST);
+        assertEquals(bridge.getPassword(), 
XMPPBridgeProviderTest.PASSWORD_TEST);
+        assertEquals(bridge.getXmppPort(), XMPPBridgeProviderTest.PORT_TEST);
+        assertEquals(bridge.isSecureConnection(), 
XMPPBridgeProviderTest.SECURE_CONNECTION_TEST);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeProviderTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeProviderTest.java
 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeProviderTest.java
new file mode 100644
index 0000000..f36d495
--- /dev/null
+++ 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeProviderTest.java
@@ -0,0 +1,105 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.DIBootstrap;
+import org.apache.cayenne.di.Injector;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.log.Slf4jJdbcEventLogger;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.tx.DefaultTransactionFactory;
+import org.apache.cayenne.tx.DefaultTransactionManager;
+import org.apache.cayenne.tx.TransactionFactory;
+import org.apache.cayenne.tx.TransactionManager;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class XMPPBridgeProviderTest {
+
+    private final DataDomain DOMAIN = new DataDomain("test");
+    private final EventManager EVENT_MANAGER = new DefaultEventManager();
+    protected static final String HOST_TEST = "somehost.com";
+    protected static final String CHAT_SERVICE_TEST = "conference";
+    protected static final String LOGIN_TEST = "login";
+    protected static final String PASSWORD_TEST = "password";
+    protected static final boolean SECURE_CONNECTION_TEST = true;
+    protected static final int PORT_TEST = 12345;
+
+    @Test
+    public void testGetXMPPBridge() throws Exception {
+        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new XMPPModule());
+        EventBridge bridge = injector.getInstance(EventBridge.class);
+
+        assertNotNull(bridge);
+        assertTrue(bridge instanceof XMPPBridge);
+    }
+
+    @Test
+    public void testUseProperties() throws Exception {
+        Module module = binder -> {
+            XMPPModule.contributeSecureConnection(binder, 
SECURE_CONNECTION_TEST);
+            XMPPModule.contributeHost(binder, HOST_TEST);
+            XMPPModule.contributePort(binder, PORT_TEST);
+            XMPPModule.contributeLogin(binder, LOGIN_TEST, PASSWORD_TEST);
+            XMPPModule.contributeChatService(binder, CHAT_SERVICE_TEST);
+        };
+
+        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new XMPPModule(), module);
+        XMPPBridge bridge = (XMPPBridge) 
injector.getInstance(EventBridge.class);
+
+        assertEquals(HOST_TEST, bridge.getXmppHost());
+        assertEquals(CHAT_SERVICE_TEST, bridge.getChatService());
+        assertEquals(LOGIN_TEST, bridge.getLoginId());
+        assertEquals(PASSWORD_TEST, bridge.getPassword());
+        assertEquals(SECURE_CONNECTION_TEST, bridge.isSecureConnection());
+        assertEquals(PORT_TEST, bridge.getXmppPort());
+    }
+
+    @Test
+    public void testUseDefaultProperties() throws Exception {
+        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new XMPPModule());
+        XMPPBridge bridge = (XMPPBridge) 
injector.getInstance(EventBridge.class);
+
+        assertEquals(XMPPBridge.DEFAULT_CHAT_SERVICE, bridge.getChatService());
+        assertEquals(0, bridge.getXmppPort());
+        assertEquals(false, bridge.isSecureConnection());
+    }
+
+    class DefaultBindings implements Module {
+        @Override
+        public void configure(Binder binder) {
+            binder.bindMap(String.class, Constants.PROPERTIES_MAP);
+            binder.bind(DataDomain.class).toInstance(DOMAIN);
+            binder.bind(EventManager.class).toInstance(EVENT_MANAGER);
+            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
+            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
+            binder.bind(JdbcEventLogger.class).to(Slf4jJdbcEventLogger.class);
+            
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeTest.java 
b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeTest.java
new file mode 100644
index 0000000..5422c3a
--- /dev/null
+++ b/cayenne-xmpp/src/test/java/org/apache/cayenne/event/XMPPBridgeTest.java
@@ -0,0 +1,54 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  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.
+ ****************************************************************/
+
+package org.apache.cayenne.event;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ */
+public class XMPPBridgeTest {
+
+    @Test
+    public void testEventSerialization() throws Exception {
+        Map<String, String> info = new HashMap<>();
+        info.put("a", "b");
+        CayenneEvent e = new CayenneEvent(this, this, info);
+
+        String string = XMPPBridge.serializeToString(e);
+        assertNotNull(string);
+
+        Object copy = XMPPBridge.deserializeFromString(string);
+        assertNotNull(copy);
+        assertTrue(copy instanceof CayenneEvent);
+
+        CayenneEvent e2 = (CayenneEvent) copy;
+        assertEquals(info, e2.getInfo());
+        assertNull(e2.getPostedBy());
+        assertNull(e2.getSource());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/pom.xml
----------------------------------------------------------------------
diff --git a/eventbridges/cayenne-jgroups/pom.xml 
b/eventbridges/cayenne-jgroups/pom.xml
deleted file mode 100644
index 3d0944e..0000000
--- a/eventbridges/cayenne-jgroups/pom.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  ~   Licensed to the Apache Software Foundation (ASF) under one
-  ~  or more contributor license agreements.  See the NOTICE file
-  ~  distributed with this work for additional information
-  ~  regarding copyright ownership.  The ASF licenses this file
-  ~  to you under the Apache License, Version 2.0 (the
-  ~  "License"); you may not use this file except in compliance
-  ~  with the License.  You may obtain a copy of the License at
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  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.
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
-    <parent>
-        <artifactId>cayenne-eventbridges-parent</artifactId>
-        <groupId>org.apache.cayenne</groupId>
-        <version>4.1.M2-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>cayenne-jgroups</artifactId>
-    <name>cayenne-jgroups: Cayenne JGroups Event bridge</name>
-    <packaging>jar</packaging>
-
-    <dependencies>
-        <dependency>
-            <groupId>jgroups</groupId>
-            <artifactId>jgroups-all</artifactId>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsModule.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsModule.java
 
b/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsModule.java
deleted file mode 100644
index 77738c3..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsModule.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.di.Binder;
-import org.apache.cayenne.di.MapBuilder;
-import org.apache.cayenne.di.Module;
-
-/**
- * @since 4.0
- */
-public class JGroupsModule implements Module {
-
-    /**
-     * A DI container key for the Map&lt;String, String&gt; storing
-     * {@link org.apache.cayenne.event.JavaGroupsBridge} properties
-     *
-     * @since 4.0
-     */
-    public static final String JAVA_GROUPS_BRIDGE_PROPERTIES_MAP = 
"cayenne.server.java_group_bridge";
-
-    public static void contributeMulticastAddress(Binder binder, String 
address) {
-        
contributeProperties(binder).put(JavaGroupsBridge.MCAST_ADDRESS_PROPERTY, 
address);
-    }
-
-    public static void contributeMulticastPort(Binder binder, int port) {
-        contributeProperties(binder).put(JavaGroupsBridge.MCAST_PORT_PROPERTY, 
Integer.toString(port));
-    }
-
-    public static void contributeConfigUrl(Binder binder, String config) {
-        
contributeProperties(binder).put(JavaGroupsBridge.JGROUPS_CONFIG_URL_PROPERTY, 
config);
-    }
-
-    private static MapBuilder<String> contributeProperties(Binder binder) {
-        return binder.bindMap(String.class, JAVA_GROUPS_BRIDGE_PROPERTIES_MAP);
-    }
-
-    @Override
-    public void configure(Binder binder) {
-        // init properties' defaults
-        contributeMulticastAddress(binder, 
JavaGroupsBridge.MCAST_ADDRESS_DEFAULT);
-        contributeMulticastPort(binder, 
JavaGroupsBridge.MCAST_PORT_DEFAULT_INT);
-
-        
binder.bind(EventBridge.class).toProvider(JavaGroupsBridgeProvider.class);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsServerModuleProvider.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsServerModuleProvider.java
 
b/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsServerModuleProvider.java
deleted file mode 100644
index 60c5bcd..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JGroupsServerModuleProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
-import org.apache.cayenne.configuration.server.ServerModule;
-import org.apache.cayenne.di.Module;
-
-/**
- * @since 4.0
- */
-public class JGroupsServerModuleProvider implements 
CayenneServerModuleProvider {
-
-    @Override
-    public Module module() {
-        return new JGroupsModule();
-    }
-
-    @Override
-    public Class<? extends Module> moduleType() {
-        return JGroupsModule.class;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public Collection<Class<? extends Module>> overrides() {
-        Collection modules = Collections.singletonList(ServerModule.class);
-        return modules;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
 
b/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
deleted file mode 100644
index cd7bae2..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.jgroups.Channel;
-import org.jgroups.JChannel;
-import org.jgroups.Message;
-import org.jgroups.MessageListener;
-import org.jgroups.blocks.PullPushAdapter;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Implementation of EventBridge that passes and receives events via JavaGroups
- * communication software.
- * 
- * @since 1.1
- */
-public class JavaGroupsBridge extends EventBridge implements MessageListener {
-
-    public static final String MCAST_ADDRESS_DEFAULT = "228.0.0.5";
-    public static final int MCAST_PORT_DEFAULT_INT = 22222;
-    public static final String MCAST_PORT_DEFAULT = 
Integer.toString(MCAST_PORT_DEFAULT_INT);
-
-    public static final String MCAST_ADDRESS_PROPERTY = 
"cayenne.JavaGroupsBridge.mcast.address";
-    public static final String MCAST_PORT_PROPERTY = 
"cayenne.JavaGroupsBridge.mcast.port";
-
-    /**
-     * Defines a property for JavaGroups XML configuration file.
-     */
-    public static final String JGROUPS_CONFIG_URL_PROPERTY = 
"javagroupsbridge.config.url";
-
-    // TODO: Meaning of "state" in JGroups is not yet clear to me
-    protected byte[] state;
-
-    protected Channel channel;
-    protected PullPushAdapter adapter;
-    protected String multicastAddress;
-    protected String multicastPort;
-    protected String configURL;
-
-    /**
-     * Creates new instance of JavaGroupsBridge.
-     */
-    public JavaGroupsBridge(EventSubject localSubject, String externalSubject) 
{
-        super(localSubject, externalSubject);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public JavaGroupsBridge(Collection<EventSubject> localSubjects, String 
externalSubject) {
-        super(localSubjects, externalSubject);
-    }
-
-    /**
-     * @since 4.0
-     */
-    public JavaGroupsBridge(Collection<EventSubject> localSubjects, String 
externalSubject, Map<String, String> properties) {
-        super(localSubjects, externalSubject);
-
-        // configure properties
-        String multicastAddress = properties.get(MCAST_ADDRESS_PROPERTY);
-        String multicastPort = properties.get(MCAST_PORT_PROPERTY);
-
-        this.configURL = properties.get(JGROUPS_CONFIG_URL_PROPERTY);
-        this.multicastAddress = (multicastAddress != null) ? multicastAddress 
: MCAST_ADDRESS_DEFAULT;
-        this.multicastPort = (multicastPort != null) ? multicastPort : 
MCAST_PORT_DEFAULT;
-    }
-
-    public String getConfigURL() {
-        return configURL;
-    }
-
-    public void setConfigURL(String configURL) {
-        this.configURL = configURL;
-    }
-
-    public String getMulticastAddress() {
-        return multicastAddress;
-    }
-
-    public void setMulticastAddress(String multicastAddress) {
-        this.multicastAddress = multicastAddress;
-    }
-
-    public String getMulticastPort() {
-        return multicastPort;
-    }
-
-    public void setMulticastPort(String multicastPort) {
-        this.multicastPort = multicastPort;
-    }
-
-    public byte[] getState() {
-        return state;
-    }
-
-    public void setState(byte[] state) {
-        this.state = state;
-    }
-
-    /**
-     * Implementation of org.javagroups.MessageListener - a callback method to 
process
-     * incoming messages.
-     */
-    public void receive(Message message) {
-        try {
-            CayenneEvent event = messageObjectToEvent((Serializable) 
message.getObject());
-            if (event != null) {
-
-                onExternalEvent(event);
-            }
-        }
-        catch (Exception ex) {
-            // TODO: Andrus, 2/8/2006 logging... Log4J was removed to make 
this usable on
-            // the client
-        }
-    }
-
-    @Override
-    protected void startupExternal() throws Exception {
-        // TODO: need to do more research to figure out the best default 
transport
-        // settings
-        // to avoid fragmentation, etc.
-
-        // if config file is set, use it, otherwise use a default
-        // set of properties, trying to configure multicast address and port
-        if (configURL != null) {
-            channel = new JChannel(configURL);
-        }
-        else {
-            String configString = buildConfigString();
-            channel = new JChannel(configString);
-        }
-
-        // Important - discard messages from self
-        channel.setOpt(Channel.LOCAL, Boolean.FALSE);
-        channel.connect(externalSubject);
-
-        if (receivesExternalEvents()) {
-            adapter = new PullPushAdapter(channel, this);
-        }
-    }
-
-    /**
-     * Creates JavaGroups configuration String, using preconfigured multicast 
port and
-     * address.
-     */
-    protected String buildConfigString() {
-        if (multicastAddress == null) {
-            throw new IllegalStateException("'multcastAddress' is not set");
-        }
-
-        if (multicastPort == null) {
-            throw new IllegalStateException("'multcastPort' is not set");
-        }
-
-        return "UDP(mcast_addr="
-                + multicastAddress
-                + ";mcast_port="
-                + multicastPort
-                + ";ip_ttl=32):"
-                + "PING(timeout=3000;num_initial_members=6):"
-                + "FD(timeout=3000):"
-                + "VERIFY_SUSPECT(timeout=1500):"
-                + 
"pbcast.NAKACK(gc_lag=10;retransmit_timeout=600,1200,2400,4800):"
-                + "pbcast.STABLE(desired_avg_gossip=10000):"
-                + "FRAG:"
-                + "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;"
-                + "shun=true;print_local_addr=false)";
-    }
-
-    @Override
-    protected void shutdownExternal() throws Exception {
-        try {
-            if (adapter != null) {
-                adapter.stop();
-            }
-
-            channel.close();
-        }
-        finally {
-            adapter = null;
-            channel = null;
-        }
-    }
-
-    @Override
-    protected void sendExternalEvent(CayenneEvent localEvent) throws Exception 
{
-        Message message = new Message(null, null, 
eventToMessageObject(localEvent));
-        channel.send(message);
-    }
-
-    /**
-     * Converts CayenneEvent to a serializable object that will be sent via 
JMS. Default
-     * implementation simply returns the event, but subclasses can customize 
this
-     * behavior.
-     */
-    protected Serializable eventToMessageObject(CayenneEvent event) throws 
Exception {
-        return event;
-    }
-
-    /**
-     * Converts a Serializable instance to CayenneEvent. Returns null if the 
object is not
-     * supported. Default implementation simply tries to cast the object to 
CayenneEvent,
-     * but subclasses can customize this behavior.
-     */
-    protected CayenneEvent messageObjectToEvent(Serializable object) throws 
Exception {
-        return (object instanceof CayenneEvent) ? (CayenneEvent) object : null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
 
b/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
deleted file mode 100644
index 302e5ca..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Factory to create JavaGroupsBridge instances. If JavaGroups library is not 
installed
- * this factory will return a noop EventBridge as a failover mechanism.
- * <p/>
- * For further information about JavaGroups consult the <a 
href="http://www.jgroups.org/";>documentation</a>.
- *
- * @since 1.1
- */
-public class JavaGroupsBridgeFactory implements EventBridgeFactory {
-
-    /**
-     * Creates a JavaGroupsBridge instance. Since JavaGroups is not shipped 
with Cayenne
-     * and should be installed separately, a common misconfiguration problem 
may be the
-     * absence of JavaGroups jar file. This factory returns a dummy noop 
EventBridge, if
-     * this is the case. This would allow the application to continue to run, 
but without
-     * remote notifications.
-     */
-    public EventBridge createEventBridge(
-            Collection<EventSubject> localSubjects,
-            String externalSubject,
-            Map<String, String> properties) {
-        return new JavaGroupsBridge(localSubjects, externalSubject, 
properties);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
 
b/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
deleted file mode 100644
index 983aa7f..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.access.DataRowStore;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.di.DIRuntimeException;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.di.Provider;
-
-import java.util.Collections;
-import java.util.Map;
-
-public class JavaGroupsBridgeProvider implements Provider<EventBridge> {
-
-    @Inject
-    protected DataDomain dataDomain;
-
-    @Inject(JGroupsModule.JAVA_GROUPS_BRIDGE_PROPERTIES_MAP)
-    Map<String, String> properties;
-
-    @Override
-    public EventBridge get() throws DIRuntimeException {
-        EventSubject snapshotEventSubject = 
EventSubject.getSubject(DataRowStore.class, dataDomain.getName());
-
-        return new JavaGroupsBridge(
-                Collections.singleton(snapshotEventSubject),
-                EventBridge.convertToExternalSubject(snapshotEventSubject),
-                properties);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
 
b/eventbridges/cayenne-jgroups/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
deleted file mode 100644
index b6c6632..0000000
--- 
a/eventbridges/cayenne-jgroups/src/main/resources/META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider
+++ /dev/null
@@ -1,20 +0,0 @@
-##################################################################
-#   Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  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.
-##################################################################
-
-org.apache.cayenne.event.JGroupsServerModuleProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/CayenneJGroupsModuleProviderTest.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/CayenneJGroupsModuleProviderTest.java
 
b/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/CayenneJGroupsModuleProviderTest.java
deleted file mode 100644
index 320d490..0000000
--- 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/CayenneJGroupsModuleProviderTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
-import org.apache.cayenne.unit.util.ModuleProviderChecker;
-import org.junit.Test;
-
-/**
- * @since 4.0
- */
-public class CayenneJGroupsModuleProviderTest {
-
-    @Test
-    public void testAutoLoadable() {
-        
ModuleProviderChecker.testProviderPresent(JGroupsServerModuleProvider.class, 
CayenneServerModuleProvider.class);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
 
b/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
deleted file mode 100644
index 694dc24..0000000
--- 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.junit.Test;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- */
-public class JavaGroupsBridgeFactoryTest {
-
-    protected Collection<EventSubject> subjects = Collections.singleton(new 
EventSubject("test"));
-    protected String externalSubject = "subject";
-
-    @Test
-    public void testCreateEventBridge() throws Exception {
-        EventBridge bridge = new JavaGroupsBridgeFactory().createEventBridge(
-                subjects,
-                externalSubject,
-                Collections.<String, String>emptyMap());
-
-        assertNotNull(bridge);
-        assertTrue(bridge instanceof JavaGroupsBridge);
-        assertEquals(subjects, bridge.getLocalSubjects());
-        assertEquals(externalSubject, bridge.getExternalSubject());
-    }
-
-    @Test
-    public void testUseProperties() throws Exception {
-        JavaGroupsBridgeFactory bridgeFactory = new JavaGroupsBridgeFactory();
-
-        Map<String, String> properties = new HashMap<>();
-        properties.put(JavaGroupsBridge.MCAST_ADDRESS_PROPERTY, 
JavaGroupsBridgeProviderTest.MCAST_ADDRESS_TEST);
-        properties.put(JavaGroupsBridge.MCAST_PORT_PROPERTY, 
JavaGroupsBridgeProviderTest.MCAST_PORT_TEST);
-        properties.put(JavaGroupsBridge.JGROUPS_CONFIG_URL_PROPERTY, 
JavaGroupsBridgeProviderTest.CONFIG_URL_TEST);
-
-        JavaGroupsBridge bridge = (JavaGroupsBridge) 
bridgeFactory.createEventBridge(
-                subjects,
-                externalSubject,
-                properties);
-
-        assertEquals(bridge.getMulticastAddress(), 
JavaGroupsBridgeProviderTest.MCAST_ADDRESS_TEST);
-        assertEquals(bridge.getMulticastPort(), 
JavaGroupsBridgeProviderTest.MCAST_PORT_TEST);
-        assertEquals(bridge.getConfigURL(), 
JavaGroupsBridgeProviderTest.CONFIG_URL_TEST);
-    }
-
-    @Test
-    public void testUseDefaultProperties() throws Exception {
-        JavaGroupsBridgeFactory bridgeFactory = new JavaGroupsBridgeFactory();
-        JavaGroupsBridge bridge = (JavaGroupsBridge) 
bridgeFactory.createEventBridge(
-                subjects,
-                externalSubject,
-                Collections.<String, String>emptyMap());
-
-        assertEquals(bridge.getMulticastAddress(), 
JavaGroupsBridge.MCAST_ADDRESS_DEFAULT);
-        assertEquals(bridge.getMulticastPort(), 
JavaGroupsBridge.MCAST_PORT_DEFAULT);
-        assertEquals(bridge.getConfigURL(), null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeProviderTest.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeProviderTest.java
 
b/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeProviderTest.java
deleted file mode 100644
index 00232d4..0000000
--- 
a/eventbridges/cayenne-jgroups/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeProviderTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.di.Binder;
-import org.apache.cayenne.di.DIBootstrap;
-import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.di.Module;
-import org.apache.cayenne.log.Slf4jJdbcEventLogger;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.tx.DefaultTransactionFactory;
-import org.apache.cayenne.tx.DefaultTransactionManager;
-import org.apache.cayenne.tx.TransactionFactory;
-import org.apache.cayenne.tx.TransactionManager;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class JavaGroupsBridgeProviderTest {
-
-    private final DataDomain DOMAIN = new DataDomain("test");
-    private final EventManager EVENT_MANAGER = new DefaultEventManager();
-    protected static final String MCAST_ADDRESS_TEST = "192.168.0.0";
-    protected static final String MCAST_PORT_TEST = "1521";
-    protected static final String CONFIG_URL_TEST = "somehost.com";
-
-    @Test
-    public void testGetJavaGroupsBridge() throws Exception {
-        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new JGroupsModule());
-        EventBridge bridge = injector.getInstance(EventBridge.class);
-
-        assertNotNull(bridge);
-        assertTrue(bridge instanceof JavaGroupsBridge);
-    }
-
-    @Test
-    public void testUseProperties() throws Exception {
-        Module module = binder -> {
-            JGroupsModule.contributeMulticastAddress(binder, 
MCAST_ADDRESS_TEST);
-            JGroupsModule.contributeMulticastPort(binder, 
Integer.parseInt(MCAST_PORT_TEST));
-            JGroupsModule.contributeConfigUrl(binder, CONFIG_URL_TEST);
-        };
-
-        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new JGroupsModule(), module);
-        JavaGroupsBridge bridge = (JavaGroupsBridge) 
injector.getInstance(EventBridge.class);
-
-        assertEquals(MCAST_ADDRESS_TEST, bridge.getMulticastAddress());
-        assertEquals(MCAST_PORT_TEST, bridge.getMulticastPort());
-        assertEquals(CONFIG_URL_TEST, bridge.getConfigURL());
-    }
-
-    @Test
-    public void testUseDefaultProperties() throws Exception {
-        Injector injector = DIBootstrap.createInjector(new DefaultBindings(), 
new JGroupsModule());
-        JavaGroupsBridge bridge = (JavaGroupsBridge) 
injector.getInstance(EventBridge.class);
-
-        assertEquals(JavaGroupsBridge.MCAST_ADDRESS_DEFAULT, 
bridge.getMulticastAddress());
-        assertEquals(JavaGroupsBridge.MCAST_PORT_DEFAULT, 
bridge.getMulticastPort());
-        assertEquals(null, bridge.getConfigURL());
-    }
-
-    class DefaultBindings implements Module {
-        @Override
-        public void configure(Binder binder) {
-            binder.bindMap(String.class, Constants.PROPERTIES_MAP);
-            binder.bind(DataDomain.class).toInstance(DOMAIN);
-            binder.bind(EventManager.class).toInstance(EVENT_MANAGER);
-            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-            binder.bind(JdbcEventLogger.class).to(Slf4jJdbcEventLogger.class);
-            
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jms/pom.xml
----------------------------------------------------------------------
diff --git a/eventbridges/cayenne-jms/pom.xml b/eventbridges/cayenne-jms/pom.xml
deleted file mode 100644
index 6ae9192..0000000
--- a/eventbridges/cayenne-jms/pom.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  ~   Licensed to the Apache Software Foundation (ASF) under one
-  ~  or more contributor license agreements.  See the NOTICE file
-  ~  distributed with this work for additional information
-  ~  regarding copyright ownership.  The ASF licenses this file
-  ~  to you under the Apache License, Version 2.0 (the
-  ~  "License"); you may not use this file except in compliance
-  ~  with the License.  You may obtain a copy of the License at
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  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.
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
-    <parent>
-        <artifactId>cayenne-eventbridges-parent</artifactId>
-        <groupId>org.apache.cayenne</groupId>
-        <version>4.1.M2-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>cayenne-jms</artifactId>
-    <name>cayenne-jms: Cayenne JMS Event bridge</name>
-    <packaging>jar</packaging>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-jms_1.1_spec</artifactId>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridge.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridge.java
 
b/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridge.java
deleted file mode 100644
index 0b746fc..0000000
--- 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridge.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.util.IDUtil;
-
-import javax.jms.Message;
-import javax.jms.MessageFormatException;
-import javax.jms.MessageListener;
-import javax.jms.ObjectMessage;
-import javax.jms.Session;
-import javax.jms.Topic;
-import javax.jms.TopicConnection;
-import javax.jms.TopicConnectionFactory;
-import javax.jms.TopicPublisher;
-import javax.jms.TopicSession;
-import javax.jms.TopicSubscriber;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingException;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Implementation of EventBridge that passes and receives events via JMS (Java 
Messaging
- * Service). JMSBridge uses "publish/subscribe" model for communication with 
external
- * agents.
- * 
- * @since 1.1
- */
-public class JMSBridge extends EventBridge implements MessageListener {
-
-    // this is an OpenJMS default for the factory name. Likely it won't work 
with
-    // anything else
-    public static final String TOPIC_CONNECTION_FACTORY_DEFAULT = 
"JmsTopicConnectionFactory";
-
-    public static final String TOPIC_CONNECTION_FACTORY_PROPERTY = 
"cayenne.JMSBridge.topic.connection.factory";
-
-    static final String VM_ID = new 
String(IDUtil.pseudoUniqueByteSequence16());
-    static final String VM_ID_PROPERTY = "VM_ID";
-
-    protected String topicConnectionFactoryName;
-
-    protected TopicConnection sendConnection;
-    protected TopicSession sendSession;
-    protected TopicConnection receivedConnection;
-    protected TopicPublisher publisher;
-    protected TopicSubscriber subscriber;
-
-    public JMSBridge(EventSubject localSubject, String externalSubject) {
-        super(localSubject, externalSubject);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public JMSBridge(Collection<EventSubject> localSubjects, String 
externalSubject) {
-        super(localSubjects, externalSubject);
-    }
-
-    /**
-     * @since 4.0
-     */
-    public JMSBridge(Collection<EventSubject> localSubjects, String 
externalSubject, Map<String, String> properties) {
-        super(localSubjects, externalSubject);
-
-        // configure properties
-        String topicConnectionFactory = properties
-                .get(TOPIC_CONNECTION_FACTORY_PROPERTY);
-
-        this.topicConnectionFactoryName = (topicConnectionFactory != null)
-                ? topicConnectionFactory
-                : TOPIC_CONNECTION_FACTORY_DEFAULT;
-    }
-
-    /**
-     * JMS MessageListener implementation. Injects received events to the 
EventManager
-     * local event queue.
-     */
-    public void onMessage(Message message) {
-
-        try {
-            Object vmID = message.getObjectProperty(JMSBridge.VM_ID_PROPERTY);
-            if (JMSBridge.VM_ID.equals(vmID)) {
-                return;
-            }
-
-            if (!(message instanceof ObjectMessage)) {
-                return;
-            }
-
-            ObjectMessage objectMessage = (ObjectMessage) message;
-            CayenneEvent event = 
messageObjectToEvent(objectMessage.getObject());
-            if (event != null) {
-                onExternalEvent(event);
-            }
-
-        }
-        catch (MessageFormatException mfex) {
-            // TODO: Andrus, 2/8/2006 logging... Log4J was removed to make 
this usable on
-            // the client
-        }
-        catch (Exception ex) {
-            // TODO: Andrus, 2/8/2006 logging... Log4J was removed to make 
this usable on
-            // the client
-        }
-    }
-
-    /**
-     * @return Name of javax.jms.TopicConnectionFactory accessible via JNDI.
-     */
-    public String getTopicConnectionFactoryName() {
-        return topicConnectionFactoryName;
-    }
-
-    public void setTopicConnectionFactoryName(String name) {
-        this.topicConnectionFactoryName = name;
-    }
-
-    /**
-     * Starts up JMS machinery for "publish/subscribe" model.
-     */
-    @Override
-    protected void startupExternal() throws Exception {
-        Context jndiContext = new InitialContext();
-        TopicConnectionFactory connectionFactory = (TopicConnectionFactory) 
jndiContext
-                .lookup(topicConnectionFactoryName);
-
-        Topic topic = null;
-
-        try {
-            topic = (Topic) jndiContext.lookup(externalSubject);
-        }
-        catch (NameNotFoundException ex) {
-            // can't find topic, try to create it
-            topic = topicNotFound(jndiContext, ex);
-
-            if (topic == null) {
-                throw ex;
-            }
-        }
-
-        // config publisher
-        if (receivesLocalEvents()) {
-            this.sendConnection = connectionFactory.createTopicConnection();
-            this.sendSession = sendConnection.createTopicSession(
-                    false,
-                    Session.AUTO_ACKNOWLEDGE);
-            this.publisher = sendSession.createPublisher(topic);
-        }
-
-        // config subscriber
-        if (receivesExternalEvents()) {
-            this.receivedConnection = 
connectionFactory.createTopicConnection();
-            this.subscriber = receivedConnection.createTopicSession(
-                    false,
-                    Session.AUTO_ACKNOWLEDGE).createSubscriber(topic);
-            this.subscriber.setMessageListener(this);
-            this.receivedConnection.start();
-        }
-    }
-
-    /**
-     * Attempts to create missing Topic. Since Topic creation is 
JMS-implementation
-     * specific, this task is left to subclasses. Current implementation 
simply rethrows
-     * the exception.
-     */
-    protected Topic topicNotFound(Context jndiContext, NamingException ex)
-            throws Exception {
-        throw ex;
-    }
-
-    /**
-     * Closes all resources used to communicate via JMS.
-     */
-    @Override
-    protected void shutdownExternal() throws Exception {
-        Exception lastException = null;
-
-        if (publisher != null) {
-            try {
-                publisher.close();
-            }
-            catch (Exception ex) {
-                lastException = ex;
-            }
-        }
-
-        if (subscriber != null) {
-            try {
-                subscriber.close();
-            }
-            catch (Exception ex) {
-                lastException = ex;
-            }
-        }
-
-        if (receivedConnection != null) {
-            try {
-                receivedConnection.close();
-            }
-            catch (Exception ex) {
-                lastException = ex;
-            }
-        }
-
-        if (sendSession != null) {
-            try {
-                sendSession.close();
-            }
-            catch (Exception ex) {
-                lastException = ex;
-            }
-        }
-
-        if (sendConnection != null) {
-            try {
-                sendConnection.close();
-            }
-            catch (Exception ex) {
-                lastException = ex;
-            }
-        }
-
-        publisher = null;
-        subscriber = null;
-        receivedConnection = null;
-        sendConnection = null;
-        sendSession = null;
-
-        if (lastException != null) {
-            throw lastException;
-        }
-    }
-
-    @Override
-    protected void sendExternalEvent(CayenneEvent localEvent) throws Exception 
{
-        ObjectMessage message = sendSession
-                .createObjectMessage(eventToMessageObject(localEvent));
-        message.setObjectProperty(JMSBridge.VM_ID_PROPERTY, JMSBridge.VM_ID);
-        publisher.publish(message);
-    }
-
-    /**
-     * Converts CayenneEvent to a serializable object that will be sent via 
JMS. Default
-     * implementation simply returns the event, but subclasses can customize 
this
-     * behavior.
-     */
-    protected Serializable eventToMessageObject(CayenneEvent event) throws 
Exception {
-        return event;
-    }
-
-    /**
-     * Converts a Serializable instance to CayenneEvent. Returns null if the 
object is not
-     * supported. Default implementation simply tries to cast the object to 
CayenneEvent,
-     * but subclasses can customize this behavior.
-     */
-    protected CayenneEvent messageObjectToEvent(Serializable object) throws 
Exception {
-        return (object instanceof CayenneEvent) ? (CayenneEvent) object : null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
 
b/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
deleted file mode 100644
index b7772d8..0000000
--- 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Factory to create JMSBridge instances.
- * 
- * @since 1.1
- */
-public class JMSBridgeFactory implements EventBridgeFactory {
-
-    /**
-     * @since 1.2
-     */
-    public EventBridge createEventBridge(Collection<EventSubject> 
localSubjects, String externalSubject, Map<String, String> properties) {
-        return new JMSBridge(localSubjects, externalSubject, properties);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ab1fd0bf/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
----------------------------------------------------------------------
diff --git 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
 
b/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
deleted file mode 100644
index 6a06faa..0000000
--- 
a/eventbridges/cayenne-jms/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  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.
- ****************************************************************/
-
-package org.apache.cayenne.event;
-
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.access.DataRowStore;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.di.DIRuntimeException;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.di.Provider;
-
-import java.util.Collections;
-import java.util.Map;
-
-public class JMSBridgeProvider implements Provider<EventBridge> {
-
-    @Inject
-    protected DataDomain dataDomain;
-
-    @Inject(JMSModule.JMS_BRIDGE_PROPERTIES_MAP)
-    Map<String, String> properties;
-
-    @Override
-    public EventBridge get() throws DIRuntimeException {
-        EventSubject snapshotEventSubject = 
EventSubject.getSubject(DataRowStore.class, dataDomain.getName());
-
-        return new JMSBridge(
-                Collections.singleton(snapshotEventSubject),
-                EventBridge.convertToExternalSubject(snapshotEventSubject),
-                properties);
-    }
-
-}

Reply via email to