+ public synchronized <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener,
+ final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges,
+ final Collection<DOMDataTreeProducer> producers) throws DOMDataTreeLoopException {
+ Preconditions.checkNotNull(listener, "listener");
+ Preconditions.checkArgument(!subtrees.isEmpty(), "Subtrees must not be empty.");
+ final ShardedDOMDataTreeListenerContext<T> listenerContext =
+ ShardedDOMDataTreeListenerContext.create(listener, subtrees, allowRxMerges);
+ try {
+ // FIXME: Add attachment of producers
+ for (final DOMDataTreeProducer producer : producers) {
+ Preconditions.checkArgument(producer instanceof ShardedDOMDataTreeProducer);
+ final ShardedDOMDataTreeProducer castedProducer = ((ShardedDOMDataTreeProducer) producer);
+ simpleLoopCheck(subtrees, castedProducer.getSubtrees());
+ // FIXME: We should also unbound listeners
+ castedProducer.boundToListener(listenerContext);
+ }
+
+ for (final DOMDataTreeIdentifier subtree : subtrees) {
+ final DOMDataTreeShard shard = shards.lookup(subtree).getValue().getInstance();
+ // FIXME: What should we do if listener is wildcard? And shards are on per
+ // node basis?
+ Preconditions.checkArgument(shard instanceof DOMStoreTreeChangePublisher,
+ "Subtree %s does not point to listenable subtree.", subtree);
+
+ listenerContext.register(subtree, (DOMStoreTreeChangePublisher) shard);
+ }
+ } catch (final Exception e) {
+ listenerContext.close();
+ throw e;
+ }
+ return new AbstractListenerRegistration<T>(listener) {
+ @Override
+ protected void removeRegistration() {
+ ShardedDOMDataTree.this.removeListener(listenerContext);
+ }
+ };
+ }
+
+ private static void simpleLoopCheck(final Collection<DOMDataTreeIdentifier> listen, final Set<DOMDataTreeIdentifier> writes)
+ throws DOMDataTreeLoopException {
+ for(final DOMDataTreeIdentifier listenPath : listen) {
+ for (final DOMDataTreeIdentifier writePath : writes) {
+ if (listenPath.contains(writePath)) {
+ throw new DOMDataTreeLoopException(String.format(
+ "Listener must not listen on parent (%s), and also writes child (%s)", listenPath,
+ writePath));
+ } else if (writePath.contains(listenPath)) {
+ throw new DOMDataTreeLoopException(
+ String.format("Listener must not write parent (%s), and also listen on child (%s)",
+ writePath, listenPath));
+ }
+ }
+ }
+ }
+
+ void removeListener(final ShardedDOMDataTreeListenerContext<?> listener) {
+ // FIXME: detach producers
+ listener.close();