You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/03/13 13:52:53 UTC

[2/6] cayenne git commit: CAY-1873 | Move DataDomain cache configuration from the Modeler and into DI

CAY-1873 | Move DataDomain cache configuration from the Modeler and into DI


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/dae15cee
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/dae15cee
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/dae15cee

Branch: refs/heads/master
Commit: dae15ceeea25a70fddeb20ad1bad83022cabf07d
Parents: 03136ff
Author: Savva Kolbachev <s....@gmail.com>
Authored: Thu Jul 2 18:32:01 2015 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Mar 10 15:54:44 2017 +0300

----------------------------------------------------------------------
 .../org/apache/cayenne/access/DataRowStore.java | 120 ++++++++---------
 .../access/DefaultDataRowStoreFactory.java      |  20 ++-
 .../apache/cayenne/configuration/Constants.java |  24 ++++
 .../server/DataDomainProvider.java              |   2 +
 .../configuration/server/ServerModule.java      |   8 +-
 .../cayenne/event/EventBridgeFactory.java       |   2 +-
 .../cayenne/event/EventBridgeProvider.java      |  60 +++++++++
 .../org/apache/cayenne/event/JMSBridge.java     |  35 ++++-
 .../apache/cayenne/event/JMSBridgeFactory.java  |  19 +--
 .../apache/cayenne/event/JMSBridgeProvider.java |  50 +++++++
 .../apache/cayenne/event/JavaGroupsBridge.java  |  33 ++++-
 .../cayenne/event/JavaGroupsBridgeFactory.java  | 109 +---------------
 .../cayenne/event/JavaGroupsBridgeProvider.java |  50 +++++++
 .../org/apache/cayenne/event/XMPPBridge.java    |  62 +++++++--
 .../apache/cayenne/event/XMPPBridgeFactory.java |  53 +-------
 .../cayenne/event/XMPPBridgeProvider.java       |  50 +++++++
 .../cayenne/access/DataRowStoreFactoryIT.java   | 119 -----------------
 .../apache/cayenne/access/DataRowStoreIT.java   |  32 -----
 .../access/DefaultDataRowStoreFactoryIT.java    | 123 ++++++++++++++++++
 .../apache/cayenne/access/MockDataRowStore.java |   7 +-
 .../server/DataContextFactoryTest.java          |   7 +
 .../server/DataDomainProviderTest.java          |   8 ++
 .../cayenne/event/JGroupsBridgeFactoryTest.java |  46 -------
 .../cayenne/event/JMSBridgeFactoryTest.java     |  77 +++++++++++
 .../cayenne/event/JMSBridgeProviderTest.java    | 119 +++++++++++++++++
 .../event/JavaGroupsBridgeFactoryTest.java      |  84 ++++++++++++
 .../event/JavaGroupsBridgeProviderTest.java     | 123 ++++++++++++++++++
 .../cayenne/event/MockEventBridgeProvider.java  |  43 ++++++
 .../cayenne/event/XMPPBridgeFactoryTest.java    |  47 ++++---
 .../cayenne/event/XMPPBridgeProviderTest.java   | 130 +++++++++++++++++++
 30 files changed, 1179 insertions(+), 483 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowStore.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowStore.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowStore.java
index 5445473..e16d834 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowStore.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowStore.java
@@ -19,17 +19,6 @@
 
 package org.apache.cayenne.access;
 
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentMap;
-
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.DataRow;
@@ -38,7 +27,6 @@ import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.access.event.SnapshotEvent;
 import org.apache.cayenne.event.EventBridge;
-import org.apache.cayenne.event.EventBridgeFactory;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.event.EventSubject;
 import org.apache.cayenne.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
@@ -46,9 +34,20 @@ import org.apache.commons.collections.ExtendedProperties;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
 /**
  * A fixed size cache of DataRows keyed by ObjectId.
- * 
+ *
  * @since 1.1
  */
 public class DataRowStore implements Serializable {
@@ -58,7 +57,18 @@ public class DataRowStore implements Serializable {
     // property keys
     public static final String SNAPSHOT_EXPIRATION_PROPERTY = "cayenne.DataRowStore.snapshot.expiration";
     public static final String SNAPSHOT_CACHE_SIZE_PROPERTY = "cayenne.DataRowStore.snapshot.size";
+
+    /**
+     * @deprecated since 4.0.M3 does nothing. Previously it used to check
+     * if need to create {@link EventBridge}.
+     */
+    @Deprecated
     public static final String REMOTE_NOTIFICATION_PROPERTY = "cayenne.DataRowStore.remote.notify";
+
+    /**
+     * @deprecated since 4.0.M3 {@link DataRowStoreFactory} establishes {@link EventBridge}.
+     */
+    @Deprecated
     public static final String EVENT_BRIDGE_FACTORY_PROPERTY = "cayenne.DataRowStore.EventBridge.factory";
 
     // default property values
@@ -66,15 +76,24 @@ public class DataRowStore implements Serializable {
     // default expiration time is 2 hours
     public static final long SNAPSHOT_EXPIRATION_DEFAULT = 2 * 60 * 60;
     public static final int SNAPSHOT_CACHE_SIZE_DEFAULT = 10000;
+
+    @Deprecated
     public static final boolean REMOTE_NOTIFICATION_DEFAULT = false;
 
     // use String for class name, since JavaGroups may not be around,
     // causing CNF exceptions
+    @Deprecated
     public static final String EVENT_BRIDGE_FACTORY_DEFAULT = "org.apache.cayenne.event.JavaGroupsBridgeFactory";
 
     protected String name;
     private int maxSize;
     protected ConcurrentMap<ObjectId, DataRow> snapshots;
+
+    /**
+     * @deprecated since 4.0.M3 does nothing. Previously it used to check
+     * if need to create {@link EventBridge}.
+     */
+    @Deprecated
     protected boolean notifyingRemoteListeners;
 
     protected transient EventManager eventManager;
@@ -87,13 +106,13 @@ public class DataRowStore implements Serializable {
     /**
      * Creates new DataRowStore with a specified name and a set of properties. If no
      * properties are defined, default values are used.
-     * 
-     * @param name DataRowStore name. Used to idenitfy this DataRowStore in events, etc.
-     *            Can't be null.
-     * @param properties Properties map used to configure DataRowStore parameters. Can be
-     *            null.
+     *
+     * @param name         DataRowStore name. Used to identify this DataRowStore in events, etc.
+     *                     Can't be null.
+     * @param properties   Properties map used to configure DataRowStore parameters. Can be
+     *                     null.
      * @param eventManager EventManager that should be used for posting and receiving
-     *            events.
+     *                     events.
      * @since 1.2
      */
     public DataRowStore(String name, Map properties, EventManager eventManager) {
@@ -126,14 +145,6 @@ public class DataRowStore implements Serializable {
                 SNAPSHOT_CACHE_SIZE_PROPERTY,
                 SNAPSHOT_CACHE_SIZE_DEFAULT);
 
-        boolean notifyRemote = propertiesWrapper.getBoolean(
-                REMOTE_NOTIFICATION_PROPERTY,
-                REMOTE_NOTIFICATION_DEFAULT);
-
-        String eventBridgeFactory = propertiesWrapper.getString(
-                EVENT_BRIDGE_FACTORY_PROPERTY,
-                EVENT_BRIDGE_FACTORY_DEFAULT);
-
         if (logger.isDebugEnabled()) {
             logger.debug("DataRowStore property "
                     + SNAPSHOT_EXPIRATION_PROPERTY
@@ -143,49 +154,25 @@ public class DataRowStore implements Serializable {
                     + SNAPSHOT_CACHE_SIZE_PROPERTY
                     + " = "
                     + maxSize);
-            logger.debug("DataRowStore property "
-                    + REMOTE_NOTIFICATION_PROPERTY
-                    + " = "
-                    + notifyRemote);
-            logger.debug("DataRowStore property "
-                    + EVENT_BRIDGE_FACTORY_PROPERTY
-                    + " = "
-                    + eventBridgeFactory);
         }
 
-        // init ivars from properties
-        this.notifyingRemoteListeners = notifyRemote;
-
         this.snapshots = new ConcurrentLinkedHashMap.Builder<ObjectId, DataRow>()
                 .maximumWeightedCapacity(maxSize)
                 .build();
 
-        // init event bridge only if we are notifying remote listeners
-        if (notifyingRemoteListeners) {
-            try {
-                EventBridgeFactory factory = (EventBridgeFactory) Class.forName(
-                        eventBridgeFactory).newInstance();
-
-                Collection<EventSubject> subjects = Collections
-                        .singleton(getSnapshotEventSubject());
-                String externalSubject = EventBridge
-                        .convertToExternalSubject(getSnapshotEventSubject());
-                this.remoteNotificationsHandler = factory.createEventBridge(
-                        subjects,
-                        externalSubject,
-                        properties);
-            }
-            catch (Exception ex) {
-                throw new CayenneRuntimeException("Error initializing DataRowStore.", ex);
-            }
+    }
 
-            startListeners();
-        }
+    protected void setEventBridge(EventBridge eventBridge) {
+        remoteNotificationsHandler = eventBridge;
+    }
+
+    protected EventBridge getEventBridge() {
+        return remoteNotificationsHandler;
     }
 
     /**
      * Updates cached snapshots for the list of objects.
-     * 
+     *
      * @since 1.2
      */
     void snapshotsUpdatedForObjects(List objects, List snapshots, boolean refresh) {
@@ -235,8 +222,7 @@ public class DataRowStore implements Serializable {
                         ((DataObject) object).setSnapshotVersion(cachedSnapshot
                                 .getVersion());
                         continue;
-                    }
-                    else {
+                    } else {
                         newSnapshot.setReplacesVersion(cachedSnapshot.getVersion());
                     }
                 }
@@ -300,7 +286,7 @@ public class DataRowStore implements Serializable {
 
     /**
      * Returns an EventManager associated with this DataRowStore.
-     * 
+     *
      * @since 1.2
      */
     public EventManager getEventManager() {
@@ -309,7 +295,7 @@ public class DataRowStore implements Serializable {
 
     /**
      * Sets an EventManager associated with this DataRowStore.
-     * 
+     *
      * @since 1.2
      */
     public void setEventManager(EventManager eventManager) {
@@ -554,10 +540,12 @@ public class DataRowStore implements Serializable {
         }
     }
 
+    @Deprecated
     public boolean isNotifyingRemoteListeners() {
         return notifyingRemoteListeners;
     }
 
+    @Deprecated
     public void setNotifyingRemoteListeners(boolean notifyingRemoteListeners) {
         this.notifyingRemoteListeners = notifyingRemoteListeners;
     }
@@ -580,8 +568,7 @@ public class DataRowStore implements Serializable {
         if (remoteNotificationsHandler != null) {
             try {
                 remoteNotificationsHandler.shutdown();
-            }
-            catch (Exception ex) {
+            } catch (Exception ex) {
                 logger.info("Exception shutting down EventBridge.", ex);
             }
             remoteNotificationsHandler = null;
@@ -613,8 +600,7 @@ public class DataRowStore implements Serializable {
                     remoteNotificationsHandler.startup(
                             eventManager,
                             EventBridge.RECEIVE_LOCAL_EXTERNAL);
-                }
-                catch (Exception ex) {
+                } catch (Exception ex) {
                     throw new CayenneRuntimeException(
                             "Error initializing DataRowStore.",
                             ex);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultDataRowStoreFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultDataRowStoreFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultDataRowStoreFactory.java
index f6f67fc..a3397b3 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultDataRowStoreFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultDataRowStoreFactory.java
@@ -19,9 +19,12 @@
 
 package org.apache.cayenne.access;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Injector;
+import org.apache.cayenne.event.EventBridge;
 import org.apache.cayenne.event.EventManager;
 
 import java.util.Map;
@@ -34,6 +37,9 @@ import java.util.Map;
 public class DefaultDataRowStoreFactory implements DataRowStoreFactory {
 
     @Inject
+    protected Injector injector;
+
+    @Inject
     protected EventManager eventManager;
 
     @Inject(Constants.DATA_ROW_STORE_PROPERTIES_MAP)
@@ -41,7 +47,19 @@ public class DefaultDataRowStoreFactory implements DataRowStoreFactory {
 
     @Override
     public DataRowStore createDataRowStore(String name) throws DIRuntimeException {
-        return new DataRowStore(name, properties, eventManager);
+        DataRowStore store = new DataRowStore(
+                name,
+                properties,
+                eventManager);
+
+        try {
+            store.setEventBridge(injector.getInstance(EventBridge.class));
+            store.startListeners();
+        } catch (Exception ex) {
+            throw new CayenneRuntimeException("Error initializing DataRowStore.", ex);
+        }
+
+        return store;
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
index 18c42cd..9761790 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
@@ -272,4 +272,28 @@ public interface Constants {
      */
     public static final String DATA_ROW_STORE_PROPERTIES_MAP = "cayenne.server.data_row_store";
 
+    /**
+     * A DI container key for the Map&lt;String, String&gt; storing
+     * {@link org.apache.cayenne.event.JMSBridge} properties
+     *
+     * @since 4.0
+     */
+    public static final String JMS_BRIDGE_PROPERTIES_MAP = "cayenne.server.jms_bridge";
+
+    /**
+     * 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";
+
+    /**
+     * 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";
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
index b7b34c7..c630155 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
@@ -23,6 +23,7 @@ import org.apache.cayenne.DataChannel;
 import org.apache.cayenne.DataChannelFilter;
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.DataRowStoreFactory;
 import org.apache.cayenne.cache.NestedQueryCache;
 import org.apache.cayenne.cache.QueryCache;
 import org.apache.cayenne.configuration.ConfigurationTree;
@@ -113,6 +114,7 @@ public class DataDomainProvider implements Provider<DataDomain> {
 		dataDomain.setQueryCache(new NestedQueryCache(queryCache));
 		dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
 		dataDomain.setEventManager(injector.getInstance(EventManager.class));
+		dataDomain.setDataRowStoreFactory(injector.getInstance(DataRowStoreFactory.class));
 
 		dataDomain.initWithProperties(descriptor.getProperties());
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
index 2f8590d..8e24e38 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
@@ -92,6 +92,8 @@ import org.apache.cayenne.di.Module;
 import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
 import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
 import org.apache.cayenne.event.DefaultEventManager;
+import org.apache.cayenne.event.EventBridgeProvider;
+import org.apache.cayenne.event.EventBridge;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.log.CommonsJdbcEventLogger;
 import org.apache.cayenne.log.JdbcEventLogger;
@@ -292,8 +294,10 @@ public class ServerModule implements Module {
 
         binder.bind(QueryCache.class).toProvider(MapQueryCacheProvider.class);
 
-		binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-        binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);// a service to provide the main stack DataDomain
+        binder.bind(EventBridge.class).toProvider(EventBridgeProvider.class);binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
+        binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
+
+		// a service to provide the main stack DataDomain
 		binder.bind(DataDomain.class).toProvider(DataDomainProvider.class);
 
         binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeFactory.java
index 7d5ecdc..dc59d0d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeFactory.java
@@ -30,7 +30,7 @@ import java.util.Map;
 public interface EventBridgeFactory {
 
     /**
-     * Creates an EventBridge with the specified parameters.
+     * Creates an {@link EventBridge} with the specified parameters.
      * 
      * @since 1.2
      */

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeProvider.java
new file mode 100644
index 0000000..ef78fb7
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/EventBridgeProvider.java
@@ -0,0 +1,60 @@
+/*****************************************************************
+ *   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.di.DIRuntimeException;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+import java.util.Collections;
+
+public class EventBridgeProvider implements Provider<EventBridge> {
+
+    @Inject
+    protected DataDomain dataDomain;
+
+    @Override
+    public EventBridge get() throws DIRuntimeException {
+        EventSubject snapshotEventSubject = EventSubject.getSubject(DataRowStore.class.getClass(), dataDomain.getName());
+
+        return new EventBridge(
+                Collections.singleton(snapshotEventSubject),
+                EventBridge.convertToExternalSubject(snapshotEventSubject)) {
+
+            @Override
+            protected void startupExternal() throws Exception {
+
+            }
+
+            @Override
+            protected void shutdownExternal() throws Exception {
+
+            }
+
+            @Override
+            protected void sendExternalEvent(CayenneEvent localEvent) throws Exception {
+
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridge.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridge.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridge.java
index 41ce7eb..0b746fc 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridge.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridge.java
@@ -19,8 +19,7 @@
 
 package org.apache.cayenne.event;
 
-import java.io.Serializable;
-import java.util.Collection;
+import org.apache.cayenne.util.IDUtil;
 
 import javax.jms.Message;
 import javax.jms.MessageFormatException;
@@ -37,8 +36,9 @@ import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NameNotFoundException;
 import javax.naming.NamingException;
-
-import org.apache.cayenne.util.IDUtil;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
 
 /**
  * Implementation of EventBridge that passes and receives events via JMS (Java Messaging
@@ -49,8 +49,14 @@ import org.apache.cayenne.util.IDUtil;
  */
 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_PROPERRTY = "VM_ID";
+    static final String VM_ID_PROPERTY = "VM_ID";
 
     protected String topicConnectionFactoryName;
 
@@ -72,13 +78,28 @@ public class JMSBridge extends EventBridge implements MessageListener {
     }
 
     /**
+     * @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_PROPERRTY);
+            Object vmID = message.getObjectProperty(JMSBridge.VM_ID_PROPERTY);
             if (JMSBridge.VM_ID.equals(vmID)) {
                 return;
             }
@@ -235,7 +256,7 @@ public class JMSBridge extends EventBridge implements MessageListener {
     protected void sendExternalEvent(CayenneEvent localEvent) throws Exception {
         ObjectMessage message = sendSession
                 .createObjectMessage(eventToMessageObject(localEvent));
-        message.setObjectProperty(JMSBridge.VM_ID_PROPERRTY, JMSBridge.VM_ID);
+        message.setObjectProperty(JMSBridge.VM_ID_PROPERTY, JMSBridge.VM_ID);
         publisher.publish(message);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
index d727365..b7772d8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeFactory.java
@@ -29,26 +29,11 @@ import java.util.Map;
  */
 public class JMSBridgeFactory implements EventBridgeFactory {
 
-    // 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";
-
     /**
      * @since 1.2
      */
     public EventBridge createEventBridge(Collection<EventSubject> localSubjects, String externalSubject, Map<String, String> properties) {
-        JMSBridge bridge = new JMSBridge(localSubjects, externalSubject);
-
-        // configure properties
-        String topicConnectionFactory = properties
-                .get(TOPIC_CONNECTION_FACTORY_PROPERTY);
-
-        bridge.setTopicConnectionFactoryName(topicConnectionFactory != null
-                ? topicConnectionFactory
-                : TOPIC_CONNECTION_FACTORY_DEFAULT);
-
-        return bridge;
+        return new JMSBridge(localSubjects, externalSubject, properties);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.java
new file mode 100644
index 0000000..217c5b3
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JMSBridgeProvider.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 JMSBridgeProvider implements Provider<EventBridge> {
+
+    @Inject
+    protected DataDomain dataDomain;
+
+    @Inject(Constants.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);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
index e7438ef..44ea4f0 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridge.java
@@ -19,15 +19,16 @@
 
 package org.apache.cayenne.event;
 
-import java.io.Serializable;
-import java.util.Collection;
-
 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.
@@ -36,6 +37,17 @@ import org.jgroups.blocks.PullPushAdapter;
  */
 public class JavaGroupsBridge extends EventBridge implements MessageListener {
 
+    public static final String MCAST_ADDRESS_DEFAULT = "228.0.0.5";
+    public static final String MCAST_PORT_DEFAULT = "22222";
+
+    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;
 
@@ -59,6 +71,21 @@ public class JavaGroupsBridge extends EventBridge implements MessageListener {
         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;
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
index 8ad7efe..302e5ca 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeFactory.java
@@ -19,35 +19,19 @@
 
 package org.apache.cayenne.event;
 
-import java.lang.reflect.Constructor;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Map;
 
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.reflect.PropertyUtils;
-
 /**
  * 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 {
 
-    public static final String MCAST_ADDRESS_DEFAULT = "228.0.0.5";
-    public static final String MCAST_PORT_DEFAULT = "22222";
-
-    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";
-
     /**
      * Creates a JavaGroupsBridge instance. Since JavaGroups is not shipped with Cayenne
      * and should be installed separately, a common misconfiguration problem may be the
@@ -59,94 +43,7 @@ public class JavaGroupsBridgeFactory implements EventBridgeFactory {
             Collection<EventSubject> localSubjects,
             String externalSubject,
             Map<String, String> properties) {
-
-        try {
-            // sniff JavaGroups presence
-            Class.forName("org.jgroups.Channel");
-            return createJavaGroupsBridge(localSubjects, externalSubject, properties);
-        }
-        catch (Exception ex) {
-            // recover from no JavaGroups
-            return createNoopBridge();
-        }
-    }
-
-    private EventBridge createNoopBridge() {
-        return new NoopEventBridge();
+        return new JavaGroupsBridge(localSubjects, externalSubject, properties);
     }
 
-    private EventBridge createJavaGroupsBridge(
-            Collection<EventSubject> localSubjects,
-            String externalSubject,
-            Map<String, String> properties) {
-
-        // create JavaGroupsBridge using reflection to avoid triggering
-        // ClassNotFound exceptions due to JavaGroups absence.
-
-        try {
-            Constructor<?> c = Class
-                    .forName("org.apache.cayenne.event.JavaGroupsBridge")
-                    .getConstructor(Collection.class, String.class);
-
-            Object bridge = c.newInstance(localSubjects, externalSubject);
-
-            // configure properties
-            String multicastAddress = properties.get(MCAST_ADDRESS_PROPERTY);
-            String multicastPort = properties.get(MCAST_PORT_PROPERTY);
-            String configURL = properties.get(JGROUPS_CONFIG_URL_PROPERTY);
-
-            PropertyUtils.setProperty(bridge, "configURL", configURL);
-            PropertyUtils.setProperty(
-                    bridge,
-                    "multicastAddress",
-                    multicastAddress != null ? multicastAddress : MCAST_ADDRESS_DEFAULT);
-            PropertyUtils.setProperty(bridge, "multicastPort", multicastPort != null
-                    ? multicastPort
-                    : MCAST_PORT_DEFAULT);
-
-            return (EventBridge) bridge;
-        }
-        catch (Exception ex) {
-            throw new CayenneRuntimeException("Error creating JavaGroupsBridge", ex);
-        }
-    }
-
-    // mockup EventBridge
-    class NoopEventBridge extends EventBridge {
-
-        public NoopEventBridge() {
-            super(Collections.<EventSubject>emptySet(), null);
-        }
-
-        @Override
-        public boolean receivesExternalEvents() {
-            return false;
-        }
-
-        @Override
-        public boolean receivesLocalEvents() {
-            return false;
-        }
-
-        @Override
-        protected void startupExternal() {
-        }
-
-        @Override
-        protected void shutdownExternal() {
-        }
-
-        @Override
-        protected void sendExternalEvent(CayenneEvent localEvent) {
-        }
-
-        @Override
-        public void startup(EventManager eventManager, int mode, Object eventsSource) {
-            this.eventManager = eventManager;
-        }
-
-        @Override
-        public void shutdown() {
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.java
new file mode 100644
index 0000000..191872d
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/JavaGroupsBridgeProvider.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 JavaGroupsBridgeProvider implements Provider<EventBridge> {
+
+    @Inject
+    protected DataDomain dataDomain;
+
+    @Inject(Constants.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/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridge.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridge.java b/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridge.java
index a533f0c..10a1386 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridge.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridge.java
@@ -19,13 +19,9 @@
 
 package org.apache.cayenne.event;
 
-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 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;
@@ -33,9 +29,14 @@ import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.XMPPException;
 import org.jivesoftware.smack.packet.Message;
 import org.jivesoftware.smack.packet.Packet;
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.util.Base64Codec;
-import org.apache.cayenne.util.Util;
+
+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.
@@ -52,6 +53,22 @@ import org.apache.cayenne.util.Util;
  */
 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;
@@ -86,6 +103,31 @@ public class XMPPBridge extends EventBridge {
         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);
+        int port = -1;
+        if (portString != null) {
+
+            try {
+                this.xmppPort = Integer.parseInt(portString);
+            }
+            catch (NumberFormatException e) {
+                throw new CayenneRuntimeException("Invalid port: " + portString);
+            }
+        }
+    }
+
     public String getXmppHost() {
         return xmppHost;
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
index bb72158..7934752 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeFactory.java
@@ -22,8 +22,6 @@ package org.apache.cayenne.event;
 import java.util.Collection;
 import java.util.Map;
 
-import org.apache.cayenne.CayenneRuntimeException;
-
 /**
  * A factory of XMPPBridge. Note that to deploy an XMPPBridge, you need to have
  * <em>smack.jar</em> library in the runtime.
@@ -32,59 +30,12 @@ import org.apache.cayenne.CayenneRuntimeException;
  */
 public class XMPPBridgeFactory implements EventBridgeFactory {
 
-    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";
-
     @Override
     public EventBridge createEventBridge(
             Collection<EventSubject> localSubjects,
             String externalSubject,
             Map<String, String> properties) {
-
-        String chatService = properties.get(XMPP_CHAT_SERVICE_PROPERTY);
-        String host = properties.get(XMPP_HOST_PROPERTY);
-
-        String loginId = properties.get(XMPP_LOGIN_PROPERTY);
-        String password = properties.get(XMPP_PASSWORD_PROPERTY);
-
-        String secureConnectionString = properties
-                .get(XMPP_SECURE_CONNECTION_PROPERTY);
-        boolean secureConnection = "true".equalsIgnoreCase(secureConnectionString);
-
-        String portString = properties.get(XMPP_PORT_PROPERTY);
-        int port = -1;
-        if (portString != null) {
-
-            try {
-                port = Integer.parseInt(portString);
-            }
-            catch (NumberFormatException e) {
-                throw new CayenneRuntimeException("Invalid port: " + portString);
-            }
-        }
-
-        XMPPBridge bridge = new XMPPBridge(localSubjects, externalSubject);
-
-        bridge.setXmppHost(host);
-        bridge.setXmppPort(port);
-        bridge.setChatService(chatService);
-        bridge.setSecureConnection(secureConnection);
-        bridge.setLoginId(loginId);
-        bridge.setPassword(password);
-
-        return bridge;
+        return new XMPPBridge(localSubjects, externalSubject, properties);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/event/XMPPBridgeProvider.java
new file mode 100644
index 0000000..ae577f2
--- /dev/null
+++ b/cayenne-server/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(Constants.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/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreFactoryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreFactoryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreFactoryIT.java
deleted file mode 100644
index 743368c..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreFactoryIT.java
+++ /dev/null
@@ -1,119 +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.access;
-
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.configuration.server.ServerRuntime;
-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.event.DefaultEventManager;
-import org.apache.cayenne.event.EventManager;
-import org.apache.cayenne.log.CommonsJdbcEventLogger;
-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.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-@UseServerRuntime(CayenneProjects.MULTI_TIER_PROJECT)
-public class DataRowStoreFactoryIT extends ServerCase {
-
-    @Test
-    public void testGetDataRowStore() throws Exception {
-        ServerRuntime runtime = getUnitTestInjector().getInstance(ServerRuntime.class);
-        DataRowStore dataStore = runtime.getInjector().getInstance(DataRowStoreFactory.class)
-                .createDataRowStore("test");
-
-        assertNotNull(dataStore);
-    }
-
-    @Test
-    public void testGetDataRowStoreWithParameters() {
-        final DataDomain DOMAIN = new DataDomain("test");
-        final EventManager EVENT_MANAGER = new DefaultEventManager();
-        final int CACHE_SIZE = 500;
-        final int EXPIRATION_PROPERTY = 60 * 60 * 24;
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bindMap(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(CommonsJdbcEventLogger.class);
-                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-                binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP)
-                        .put(DataRowStore.SNAPSHOT_CACHE_SIZE_PROPERTY, String.valueOf(CACHE_SIZE))
-                        .put(DataRowStore.SNAPSHOT_EXPIRATION_PROPERTY, String.valueOf(EXPIRATION_PROPERTY));
-            }
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-        DataRowStore dataStore = injector.getInstance(DataRowStoreFactory.class)
-                .createDataRowStore("test");
-
-        assertNotNull(dataStore);
-        assertEquals(dataStore.maximumSize(), CACHE_SIZE);
-    }
-
-    @Test
-    public void testGetDataRowStoreWithBridge() {
-        final DataDomain DOMAIN = new DataDomain("test");
-        final EventManager EVENT_MANAGER = new DefaultEventManager();
-
-        Module testModule = new Module() {
-
-            public void configure(Binder binder) {
-                binder.bindMap(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(CommonsJdbcEventLogger.class);
-                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-                binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
-            }
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-        DataRowStore dataStore = injector.getInstance(DataRowStoreFactory.class)
-                .createDataRowStore("test");
-
-        dataStore.stopListeners();
-        dataStore.startListeners();
-        dataStore.shutdown();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreIT.java
index 54ce5a1..879e98d 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataRowStoreIT.java
@@ -64,38 +64,6 @@ public class DataRowStoreIT extends ServerCase {
         assertEquals("cacheXYZ", cache.getName());
         assertNotNull(cache.getSnapshotEventSubject());
         assertTrue(cache.getSnapshotEventSubject().getSubjectName().contains("cacheXYZ"));
-
-        assertEquals(DataRowStore.REMOTE_NOTIFICATION_DEFAULT, cache
-                .isNotifyingRemoteListeners());
-    }
-
-    @Test
-    public void testConstructorWithProperties() {
-        Map<Object, Object> props = new HashMap<Object, Object>();
-        props.put(DataRowStore.REMOTE_NOTIFICATION_PROPERTY, String
-                .valueOf(!DataRowStore.REMOTE_NOTIFICATION_DEFAULT));
-        cache = new DataRowStore(
-                "cacheXYZ",
-                props,
-                null);
-        assertEquals("cacheXYZ", cache.getName());
-        assertEquals(!DataRowStore.REMOTE_NOTIFICATION_DEFAULT, cache
-                .isNotifyingRemoteListeners());
-    }
-
-    @Test
-    public void testNotifyingRemoteListeners() {
-        cache = new DataRowStore(
-                "cacheXYZ",
-                Collections.EMPTY_MAP,
-                null);
-
-        assertEquals(DataRowStore.REMOTE_NOTIFICATION_DEFAULT, cache
-                .isNotifyingRemoteListeners());
-
-        cache.setNotifyingRemoteListeners(!DataRowStore.REMOTE_NOTIFICATION_DEFAULT);
-        assertEquals(!DataRowStore.REMOTE_NOTIFICATION_DEFAULT, cache
-                .isNotifyingRemoteListeners());
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
new file mode 100644
index 0000000..2621443
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
@@ -0,0 +1,123 @@
+/*****************************************************************
+ *   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.access;
+
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+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.event.DefaultEventManager;
+import org.apache.cayenne.event.EventBridge;
+import org.apache.cayenne.event.EventBridgeProvider;
+import org.apache.cayenne.event.EventManager;
+import org.apache.cayenne.event.MockEventBridge;
+import org.apache.cayenne.event.MockEventBridgeProvider;
+import org.apache.cayenne.log.CommonsJdbcEventLogger;
+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.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@UseServerRuntime(CayenneProjects.MULTI_TIER_PROJECT)
+public class DefaultDataRowStoreFactoryIT extends ServerCase {
+
+    @Test
+    public void testGetDataRowStore() throws Exception {
+        ServerRuntime runtime = getUnitTestInjector().getInstance(ServerRuntime.class);
+        DataRowStore dataStore = runtime.getInjector().getInstance(DataRowStoreFactory.class)
+                .createDataRowStore("test");
+
+        assertNotNull(dataStore);
+    }
+
+    @Test
+    public void testGetDataRowStoreWithParameters() {
+        final DataDomain DOMAIN = new DataDomain("test");
+        final EventManager EVENT_MANAGER = new DefaultEventManager();
+        final int CACHE_SIZE = 500;
+        final int EXPIRATION_PROPERTY = 60 * 60 * 24;
+
+        Module testModule = new Module() {
+
+            public void configure(Binder binder) {
+                binder.bindMap(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(CommonsJdbcEventLogger.class);
+                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+                binder.bind(EventBridge.class).toProvider(EventBridgeProvider.class);
+                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
+                binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP)
+                        .put(DataRowStore.SNAPSHOT_CACHE_SIZE_PROPERTY, String.valueOf(CACHE_SIZE))
+                        .put(DataRowStore.SNAPSHOT_EXPIRATION_PROPERTY, String.valueOf(EXPIRATION_PROPERTY));
+            }
+        };
+
+        Injector injector = DIBootstrap.createInjector(testModule);
+        DataRowStore dataStore = injector.getInstance(DataRowStoreFactory.class)
+                .createDataRowStore("test");
+
+        assertNotNull(dataStore);
+        assertEquals(dataStore.maximumSize(), CACHE_SIZE);
+    }
+
+    @Test
+    public void testGetDataRowStoreWithBridge() {
+        final DataDomain DOMAIN = new DataDomain("test");
+        final EventManager EVENT_MANAGER = new DefaultEventManager();
+
+        Module testModule = new Module() {
+
+            public void configure(Binder binder) {
+                binder.bindMap(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(CommonsJdbcEventLogger.class);
+                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+                binder.bind(EventBridge.class).toProvider(MockEventBridgeProvider.class);
+                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
+                binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
+            }
+        };
+
+        Injector injector = DIBootstrap.createInjector(testModule);
+        DataRowStore dataStore = injector.getInstance(DataRowStoreFactory.class)
+                .createDataRowStore("test");
+
+        assertEquals(dataStore.getEventBridge().getClass(), MockEventBridge.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/access/MockDataRowStore.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/MockDataRowStore.java b/cayenne-server/src/test/java/org/apache/cayenne/access/MockDataRowStore.java
index dba5c98..76ac2cb 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/MockDataRowStore.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/MockDataRowStore.java
@@ -19,13 +19,13 @@
 
 package org.apache.cayenne.access;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.event.MockEventManager;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * A "lightweight" DataRowStore.
  */
@@ -35,7 +35,6 @@ public class MockDataRowStore extends DataRowStore {
 
     static {
         TEST_DEFAULTS.put(DataRowStore.SNAPSHOT_CACHE_SIZE_PROPERTY, new Integer(10));
-        TEST_DEFAULTS.put(DataRowStore.REMOTE_NOTIFICATION_PROPERTY, Boolean.FALSE);
     }
 
     public MockDataRowStore() {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataContextFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataContextFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataContextFactoryTest.java
index 0304a2e..32477cb 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataContextFactoryTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataContextFactoryTest.java
@@ -35,6 +35,8 @@ 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.event.EventBridgeProvider;
+import org.apache.cayenne.event.EventBridge;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.event.MockEventManager;
 import org.apache.cayenne.log.CommonsJdbcEventLogger;
@@ -78,6 +80,8 @@ public class DataContextFactoryTest {
                 binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
                 binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
                 binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
+                binder.bind(EventBridge.class).toProvider(EventBridgeProvider.class);
+                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
                 binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
             }
         };
@@ -116,6 +120,7 @@ public class DataContextFactoryTest {
                 binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
                 binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
                 binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
+                binder.bind(EventBridge.class).toProvider(EventBridgeProvider.class);
                 binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
                 binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
             }
@@ -123,6 +128,8 @@ public class DataContextFactoryTest {
 
         Injector injector = DIBootstrap.createInjector(testModule);
 
+        domain.setDataRowStoreFactory(injector.getInstance(DataRowStoreFactory.class));
+
         DataContextFactory factory = new DataContextFactory();
         injector.injectMembers(factory);
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
index 1828a0c..54831de 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
@@ -22,6 +22,8 @@ import org.apache.cayenne.ConfigurationException;
 import org.apache.cayenne.DataChannel;
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.DataRowStoreFactory;
+import org.apache.cayenne.access.DefaultDataRowStoreFactory;
 import org.apache.cayenne.access.dbsync.DefaultSchemaUpdateStrategyFactory;
 import org.apache.cayenne.access.dbsync.SchemaUpdateStrategyFactory;
 import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
@@ -70,6 +72,8 @@ import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.Module;
 import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
 import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
+import org.apache.cayenne.event.EventBridge;
+import org.apache.cayenne.event.EventBridgeProvider;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.event.MockEventManager;
 import org.apache.cayenne.log.CommonsJdbcEventLogger;
@@ -192,6 +196,10 @@ public class DataDomainProviderTest {
 				binder.bind(RowReaderFactory.class).toInstance(mock(RowReaderFactory.class));
 				binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
 				binder.bind(SQLTemplateProcessor.class).toInstance(mock(SQLTemplateProcessor.class));
+
+                binder.bind(EventBridge.class).toProvider(EventBridgeProvider.class);
+                binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
+                binder.bindMap(Constants.DATA_ROW_STORE_PROPERTIES_MAP);
 			}
 		};
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/event/JGroupsBridgeFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/event/JGroupsBridgeFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/event/JGroupsBridgeFactoryTest.java
deleted file mode 100644
index 3a6b6c1..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/event/JGroupsBridgeFactoryTest.java
+++ /dev/null
@@ -1,46 +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 static org.junit.Assert.*;
-
-/**
- */
-public class JGroupsBridgeFactoryTest {
-
-    @Test
-    public void testCreateEventBridge() throws Exception {
-        Collection subjects = Collections.singleton(new EventSubject("test"));
-        EventBridge bridge = new JavaGroupsBridgeFactory().createEventBridge(
-                subjects,
-                "abcd",
-                Collections.EMPTY_MAP);
-
-        assertNotNull(bridge);
-        assertTrue(bridge instanceof JavaGroupsBridge);
-        assertEquals(subjects, bridge.getLocalSubjects());
-        assertEquals("abcd", bridge.getExternalSubject());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeFactoryTest.java
new file mode 100644
index 0000000..e098d4e
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeFactoryTest.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ *   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 JMSBridgeFactoryTest {
+
+    protected Collection<EventSubject> subjects = Collections.singleton(new EventSubject("test"));
+    protected String externalSubject = "subject";
+
+    @Test
+    public void testCreateEventBridge() throws Exception {
+        EventBridge bridge = new JMSBridgeFactory().createEventBridge(
+                subjects,
+                externalSubject,
+                Collections.EMPTY_MAP);
+
+        assertNotNull(bridge);
+        assertTrue(bridge instanceof JMSBridge);
+        assertEquals(subjects, bridge.getLocalSubjects());
+        assertEquals(externalSubject, bridge.getExternalSubject());
+    }
+
+    @Test
+    public void testUseProperties() throws Exception {
+        JMSBridgeFactory bridgeFactory = new JMSBridgeFactory();
+
+        Map<String, String> properties = new HashMap<String, String>();
+        properties.put(JMSBridge.TOPIC_CONNECTION_FACTORY_PROPERTY, JMSBridgeProviderTest.TOPIC_CONNECTION_FACTORY_TEST);
+
+        JMSBridge bridge = (JMSBridge) bridgeFactory.createEventBridge(
+                subjects,
+                externalSubject,
+                properties);
+
+        assertEquals(bridge.getTopicConnectionFactoryName(), JMSBridgeProviderTest.TOPIC_CONNECTION_FACTORY_TEST);
+    }
+
+    @Test
+    public void testUseDefaultProperties() throws Exception {
+        JMSBridgeFactory bridgeFactory = new JMSBridgeFactory();
+        JMSBridge bridge = (JMSBridge) bridgeFactory.createEventBridge(
+                subjects,
+                externalSubject,
+                Collections.EMPTY_MAP);
+
+        assertEquals(bridge.getTopicConnectionFactoryName(), JMSBridge.TOPIC_CONNECTION_FACTORY_DEFAULT);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeProviderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeProviderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeProviderTest.java
new file mode 100644
index 0000000..c683666
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/event/JMSBridgeProviderTest.java
@@ -0,0 +1,119 @@
+/*****************************************************************
+ *   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.CommonsJdbcEventLogger;
+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 JMSBridgeProviderTest {
+
+    private final DataDomain DOMAIN = new DataDomain("test");
+    private final EventManager EVENT_MANAGER = new DefaultEventManager();
+    protected static final String TOPIC_CONNECTION_FACTORY_TEST = "SomeTopicConnectionFactory";
+
+    @Test
+    public void testGetJMSBridge() throws Exception {
+        Module module = new Module() {
+
+            public void configure(Binder binder) {
+                binder.bindMap(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(CommonsJdbcEventLogger.class);
+                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+                binder.bind(EventBridge.class).toProvider(JMSBridgeProvider.class);
+                binder.bindMap(Constants.JMS_BRIDGE_PROPERTIES_MAP);
+            }
+        };
+
+        Injector injector = DIBootstrap.createInjector(module);
+        EventBridge bridge = injector.getInstance(EventBridge.class);
+
+        assertNotNull(bridge);
+        assertTrue(bridge instanceof JMSBridge);
+    }
+
+    @Test
+    public void testUseProperties() throws Exception {
+        Module module = new Module() {
+
+            public void configure(Binder binder) {
+                binder.bindMap(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(CommonsJdbcEventLogger.class);
+                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+                binder.bind(EventBridge.class).toProvider(JMSBridgeProvider.class);
+                binder.bindMap(Constants.JMS_BRIDGE_PROPERTIES_MAP)
+                        .put(JMSBridge.TOPIC_CONNECTION_FACTORY_PROPERTY, TOPIC_CONNECTION_FACTORY_TEST);
+            }
+        };
+
+        Injector injector = DIBootstrap.createInjector(module);
+        JMSBridge bridge = (JMSBridge) injector.getInstance(EventBridge.class);
+
+        assertEquals(JMSBridgeProviderTest.TOPIC_CONNECTION_FACTORY_TEST, bridge.getTopicConnectionFactoryName());
+    }
+
+    @Test
+    public void testUseDefaultProperties() throws Exception {
+        Module module = new Module() {
+
+            public void configure(Binder binder) {
+                binder.bindMap(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(CommonsJdbcEventLogger.class);
+                binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+                binder.bind(EventBridge.class).toProvider(JMSBridgeProvider.class);
+                binder.bindMap(Constants.JMS_BRIDGE_PROPERTIES_MAP);
+            }
+        };
+
+        Injector injector = DIBootstrap.createInjector(module);
+        JMSBridge bridge = (JMSBridge) injector.getInstance(EventBridge.class);
+
+        assertEquals(bridge.getTopicConnectionFactoryName(), JMSBridge.TOPIC_CONNECTION_FACTORY_DEFAULT);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/dae15cee/cayenne-server/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
new file mode 100644
index 0000000..3497888
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/event/JavaGroupsBridgeFactoryTest.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ *   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.EMPTY_MAP);
+
+        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<String, String>();
+        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.EMPTY_MAP);
+
+        assertEquals(bridge.getMulticastAddress(), JavaGroupsBridge.MCAST_ADDRESS_DEFAULT);
+        assertEquals(bridge.getMulticastPort(), JavaGroupsBridge.MCAST_PORT_DEFAULT);
+        assertEquals(bridge.getConfigURL(), null);
+    }
+}