You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2016/04/21 03:13:24 UTC

[25/33] curator git commit: Merge branch 'master' into CURATOR-3.0

Merge branch 'master' into CURATOR-3.0

Conflicts:
	curator-client/pom.xml
	curator-examples/pom.xml
	curator-framework/pom.xml
	curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/GetACLBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/SetACLBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/SetDataBuilderImpl.java
	curator-framework/src/main/java/org/apache/curator/framework/imps/SyncBuilderImpl.java
	curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkBackground.java
	curator-recipes/pom.xml
	curator-test/pom.xml
	curator-x-discovery-server/pom.xml
	curator-x-discovery/pom.xml
	curator-x-rpc/pom.xml
	pom.xml


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

Branch: refs/heads/CURATOR-299
Commit: 062a7d750788a187f1d41df0bf0a6a5926a78d3a
Parents: 8ef32cc 8499680
Author: randgalt <ra...@apache.org>
Authored: Thu Mar 10 17:55:14 2016 -0500
Committer: randgalt <ra...@apache.org>
Committed: Thu Mar 10 17:55:14 2016 -0500

----------------------------------------------------------------------
 .../framework/api/BackgroundEnsembleable.java   |   2 +-
 .../api/BackgroundPathAndBytesable.java         |   2 +-
 .../framework/api/BackgroundPathable.java       |   2 +-
 .../api/ErrorListenerEnsembleable.java          |  14 ++
 .../api/ErrorListenerMultiTransactionMain.java  |  16 ++
 .../api/ErrorListenerPathAndBytesable.java      |  14 ++
 .../framework/api/ErrorListenerPathable.java    |  14 ++
 .../api/ErrorListenerReconfigBuilderMain.java   |  14 ++
 .../curator/framework/api/GetConfigBuilder.java |   2 +-
 .../curator/framework/api/ReconfigBuilder.java  |   2 +-
 .../transaction/CuratorMultiTransaction.java    |   3 +-
 .../curator/framework/imps/Backgrounding.java   |  80 +++++--
 .../framework/imps/CreateBuilderImpl.java       | 236 ++++++++++---------
 .../imps/CuratorMultiTransactionImpl.java       |  55 +++--
 .../framework/imps/DeleteBuilderImpl.java       |  84 ++++---
 .../framework/imps/ExistsBuilderImpl.java       |  63 ++---
 .../framework/imps/GetACLBuilderImpl.java       |  50 ++--
 .../framework/imps/GetChildrenBuilderImpl.java  |  60 +++--
 .../framework/imps/GetConfigBuilderImpl.java    |  87 +++----
 .../framework/imps/GetDataBuilderImpl.java      |  94 ++++----
 .../framework/imps/ReconfigBuilderImpl.java     |  52 ++--
 .../imps/RemoveWatchesBuilderImpl.java          |  65 +++--
 .../framework/imps/SetACLBuilderImpl.java       |  66 ++++--
 .../framework/imps/SetDataBuilderImpl.java      |  85 ++++---
 .../curator/framework/imps/SyncBuilderImpl.java |  56 +++--
 .../framework/imps/TestFrameworkBackground.java |  49 ++++
 26 files changed, 791 insertions(+), 476 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundEnsembleable.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundEnsembleable.java
index c8b323f,0000000..5f9703a
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundEnsembleable.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundEnsembleable.java
@@@ -1,25 -1,0 +1,25 @@@
 +/**
 + * 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.curator.framework.api;
 +
 +public interface BackgroundEnsembleable<T> extends
-     Backgroundable<Ensembleable<T>>,
++    Backgroundable<ErrorListenerEnsembleable<T>>,
 +    Ensembleable<T>
 +{
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerEnsembleable.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerEnsembleable.java
index 0000000,0000000..1072baa
new file mode 100644
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerEnsembleable.java
@@@ -1,0 -1,0 +1,14 @@@
++package org.apache.curator.framework.api;
++
++public interface ErrorListenerEnsembleable<T> extends Ensembleable<T>
++{
++    /**
++     * Set an error listener for this background operation. If an exception
++     * occurs while processing the call in the background, this listener will
++     * be called
++     *
++     * @param listener the listener
++     * @return this for chaining
++     */
++    Ensembleable<T> withUnhandledErrorListener(UnhandledErrorListener listener);
++}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerMultiTransactionMain.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerMultiTransactionMain.java
index 0000000,0000000..a217004
new file mode 100644
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerMultiTransactionMain.java
@@@ -1,0 -1,0 +1,16 @@@
++package org.apache.curator.framework.api;
++
++import org.apache.curator.framework.api.transaction.CuratorMultiTransactionMain;
++
++public interface ErrorListenerMultiTransactionMain<T> extends CuratorMultiTransactionMain
++{
++    /**
++     * Set an error listener for this background operation. If an exception
++     * occurs while processing the call in the background, this listener will
++     * be called
++     *
++     * @param listener the listener
++     * @return this for chaining
++     */
++    CuratorMultiTransactionMain withUnhandledErrorListener(UnhandledErrorListener listener);
++}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerReconfigBuilderMain.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerReconfigBuilderMain.java
index 0000000,0000000..163ecc5
new file mode 100644
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ErrorListenerReconfigBuilderMain.java
@@@ -1,0 -1,0 +1,14 @@@
++package org.apache.curator.framework.api;
++
++public interface ErrorListenerReconfigBuilderMain extends ReconfigBuilderMain
++{
++    /**
++     * Set an error listener for this background operation. If an exception
++     * occurs while processing the call in the background, this listener will
++     * be called
++     *
++     * @param listener the listener
++     * @return this for chaining
++     */
++    ReconfigBuilderMain withUnhandledErrorListener(UnhandledErrorListener listener);
++}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java
index d137f28,0000000..3c926d4
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java
@@@ -1,28 -1,0 +1,28 @@@
 +/**
 + * 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.curator.framework.api;
 +
 +public interface GetConfigBuilder extends
 +    Ensembleable<byte[]>,
-     Backgroundable<Ensembleable<byte[]>>,
++    Backgroundable<ErrorListenerEnsembleable<byte[]>>,
 +    Watchable<BackgroundEnsembleable<byte[]>>,
 +    Statable<WatchBackgroundEnsembleable<byte[]>>
 +{
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java
index d8a2cc2,0000000..233558d
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java
@@@ -1,26 -1,0 +1,26 @@@
 +/**
 + * 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.curator.framework.api;
 +
 +public interface ReconfigBuilder extends
 +    ReconfigBuilderMain,
-     Backgroundable<ReconfigBuilderMain>
++    Backgroundable<ErrorListenerReconfigBuilderMain>
 +{
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/api/transaction/CuratorMultiTransaction.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/transaction/CuratorMultiTransaction.java
index 07bf191,0000000..e919a33
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/transaction/CuratorMultiTransaction.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/transaction/CuratorMultiTransaction.java
@@@ -1,27 -1,0 +1,28 @@@
 +/**
 + * 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.curator.framework.api.transaction;
 +
 +import org.apache.curator.framework.api.Backgroundable;
++import org.apache.curator.framework.api.ErrorListenerMultiTransactionMain;
 +
 +public interface CuratorMultiTransaction extends
-     Backgroundable<CuratorMultiTransactionMain>,
++    Backgroundable<ErrorListenerMultiTransactionMain>,
 +    CuratorMultiTransactionMain
 +{
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
index 57adae3,0f893d8..ace163b
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
@@@ -525,157 -508,40 +532,164 @@@ class CreateBuilderImpl implements Crea
      @Override
      public void performBackgroundOperation(final OperationAndData<PathAndBytes> operationAndData) throws Exception
      {
-         final TimeTrace trace = client.getZookeeperClient().startTracer("CreateBuilderImpl-Background");
-         
-         if(storingStat == null)
+         try
          {
-             client.getZooKeeper().create
-             (
-                 operationAndData.getData().getPath(),
-                 operationAndData.getData().getData(),
-                 acling.getAclList(operationAndData.getData().getPath()),
-                 createMode,
-                 new AsyncCallback.StringCallback()
-                 {
-                     @Override
-                     public void processResult(int rc, String path, Object ctx, String name)
-                     {
-                         trace.commit();
+             final TimeTrace trace = client.getZookeeperClient().startTracer("CreateBuilderImpl-Background");
 -            client.getZooKeeper().create
 +
-                         if ( (rc == KeeperException.Code.NONODE.intValue()) && createParentsIfNeeded )
-                         {
-                             backgroundCreateParentsThenNode(client, operationAndData, operationAndData.getData().getPath(), backgrounding, createParentsAsContainers);
-                         }
-                         else if ( (rc == KeeperException.Code.NODEEXISTS.intValue()) && setDataIfExists )
++            if(storingStat == null)
++            {
++                client.getZooKeeper().create
+                 (
+                     operationAndData.getData().getPath(),
+                     operationAndData.getData().getData(),
+                     acling.getAclList(operationAndData.getData().getPath()),
+                     createMode,
+                     new AsyncCallback.StringCallback()
+                     {
+                         @Override
+                         public void processResult(int rc, String path, Object ctx, String name)
                          {
-                             backgroundSetData(client, operationAndData, operationAndData.getData().getPath(), backgrounding);
+                             trace.commit();
+ 
+                             if ( (rc == KeeperException.Code.NONODE.intValue()) && createParentsIfNeeded )
+                             {
+                                 backgroundCreateParentsThenNode(client, operationAndData, operationAndData.getData().getPath(), backgrounding, createParentsAsContainers);
+                             }
++                            else if ( (rc == KeeperException.Code.NODEEXISTS.intValue()) && setDataIfExists )
++                            {
++                                backgroundSetData(client, operationAndData, operationAndData.getData().getPath(), backgrounding);
++                            }
+                             else
+                             {
 -                                sendBackgroundResponse(rc, path, ctx, name, operationAndData);
++                                sendBackgroundResponse(rc, path, ctx, name, null, operationAndData);
+                             }
                          }
-                         else
-                         {
-                             sendBackgroundResponse(rc, path, ctx, name, null, operationAndData);
+                     },
+                     backgrounding.getContext()
+                 );
++            }
++            else
++            {
++                client.getZooKeeper().create
++                (
++                    operationAndData.getData().getPath(),
++                    operationAndData.getData().getData(),
++                    acling.getAclList(operationAndData.getData().getPath()),
++                    createMode,
++                    new AsyncCallback.Create2Callback() {
++
++                        @Override
++                        public void processResult(int rc, String path, Object ctx, String name, Stat stat) {
++                            trace.commit();
++
++                            if ( stat != null )
++                            {
++                                storingStat.setAversion(stat.getAversion());
++                                storingStat.setCtime(stat.getCtime());
++                                storingStat.setCversion(stat.getCversion());
++                                storingStat.setCzxid(stat.getCzxid());
++                                storingStat.setDataLength(stat.getDataLength());
++                                storingStat.setEphemeralOwner(stat.getEphemeralOwner());
++                                storingStat.setMtime(stat.getMtime());
++                                storingStat.setMzxid(stat.getMzxid());
++                                storingStat.setNumChildren(stat.getNumChildren());
++                                storingStat.setPzxid(stat.getPzxid());
++                                storingStat.setVersion(stat.getVersion());
++                            }
++
++                            if ( (rc == KeeperException.Code.NONODE.intValue()) && createParentsIfNeeded )
++                            {
++                                backgroundCreateParentsThenNode(client, operationAndData, operationAndData.getData().getPath(), backgrounding, createParentsAsContainers);
++                            }
++                            else
++                            {
++                                sendBackgroundResponse(rc, path, ctx, name, stat, operationAndData);
++                            }
 +                        }
-                     }
-                 },
-                 backgrounding.getContext()
-             );
++                    },
++                    backgrounding.getContext()
++                );
++            }
          }
-         else
+         catch ( Throwable e )
          {
-             client.getZooKeeper().create
-             (
-                 operationAndData.getData().getPath(),
-                 operationAndData.getData().getData(),
-                 acling.getAclList(operationAndData.getData().getPath()),
-                 createMode,
-                 new AsyncCallback.Create2Callback() {
-                     
-                     @Override
-                     public void processResult(int rc, String path, Object ctx, String name, Stat stat) {
-                         trace.commit();
- 
-                         if ( stat != null )
-                         {
-                             storingStat.setAversion(stat.getAversion());
-                             storingStat.setCtime(stat.getCtime());
-                             storingStat.setCversion(stat.getCversion());
-                             storingStat.setCzxid(stat.getCzxid());
-                             storingStat.setDataLength(stat.getDataLength());
-                             storingStat.setEphemeralOwner(stat.getEphemeralOwner());
-                             storingStat.setMtime(stat.getMtime());
-                             storingStat.setMzxid(stat.getMzxid());
-                             storingStat.setNumChildren(stat.getNumChildren());
-                             storingStat.setPzxid(stat.getPzxid());
-                             storingStat.setVersion(stat.getVersion());
-                         }
- 
-                         if ( (rc == KeeperException.Code.NONODE.intValue()) && createParentsIfNeeded )
-                         {
-                             backgroundCreateParentsThenNode(client, operationAndData, operationAndData.getData().getPath(), backgrounding, createParentsAsContainers);
-                         }
-                         else
-                         {
-                             sendBackgroundResponse(rc, path, ctx, name, stat, operationAndData);
-                         }
-                     }
-                 },
-                 backgrounding.getContext()
-             );
+             backgrounding.checkError(e);
          }
      }
 +    
 +    @Override
 +    public CreateProtectACLCreateModePathAndBytesable<String> storingStatIn(Stat stat) {
 +        storingStat = stat;
 +        
 +        return new CreateProtectACLCreateModePathAndBytesable<String>() {
 +
 +            @Override
 +            public BackgroundPathAndBytesable<String> withACL(List<ACL> aclList) {
 +                return CreateBuilderImpl.this.withACL(aclList);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground() {
++            public ErrorListenerPathAndBytesable<String> inBackground() {
 +                return CreateBuilderImpl.this.inBackground();
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(Object context) {
 +                return CreateBuilderImpl.this.inBackground(context);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback) {
 +                return CreateBuilderImpl.this.inBackground(callback);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
 +                return CreateBuilderImpl.this.inBackground(callback, context);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, executor);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context,
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context,
 +                    Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, context, executor);
 +            }
 +
 +            @Override
 +            public String forPath(String path, byte[] data) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path, data);
 +            }
 +
 +            @Override
 +            public String forPath(String path) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path);
 +            }
 +
 +            @Override
 +            public ACLBackgroundPathAndBytesable<String> withMode(CreateMode mode) {
 +                return CreateBuilderImpl.this.withMode(mode);
 +            }
 +
 +            @Override
 +            public ACLCreateModeBackgroundPathAndBytesable<String> withProtection() {
 +                return CreateBuilderImpl.this.withProtection();
 +            }
 +
 +            @Override
 +            public ProtectACLCreateModePathAndBytesable<String> creatingParentsIfNeeded() {
 +                return CreateBuilderImpl.this.creatingParentsIfNeeded();
 +            }
 +
 +            @Override
 +            public ProtectACLCreateModePathAndBytesable<String> creatingParentContainersIfNeeded() {
 +                return CreateBuilderImpl.this.creatingParentContainersIfNeeded();
 +            }  
 +        };
 +    }
  
      private static String getProtectedPrefix(String protectedId)
      {
@@@ -804,141 -634,6 +818,141 @@@
              }
          };
      }
 +    
 +    private CreateBackgroundModeACLable asCreateBackgroundModeACLable()
 +    {
 +        return new CreateBackgroundModeACLable() {
 +            
 +            @Override
 +            public BackgroundPathAndBytesable<String> withACL(List<ACL> aclList) {
 +                return CreateBuilderImpl.this.withACL(aclList);
 +            }
 +            
 +            @Override
 +            public ACLBackgroundPathAndBytesable<String> withMode(CreateMode mode) {
 +                return CreateBuilderImpl.this.withMode(mode);
 +            }
 +            
 +            @Override
 +            public String forPath(String path) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path);
 +            }
 +            
 +            @Override
 +            public String forPath(String path, byte[] data) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path, data);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context, Executor executor) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context, Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, context, executor);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, executor);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
 +                return CreateBuilderImpl.this.inBackground(callback, context);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback) {
 +                return CreateBuilderImpl.this.inBackground(callback);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(Object context) {
 +                return CreateBuilderImpl.this.inBackground(context);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground() {
++            public ErrorListenerPathAndBytesable<String> inBackground() {
 +                return CreateBuilderImpl.this.inBackground();
 +            }
 +            
 +            @Override
 +            public ACLPathAndBytesable<String> withProtectedEphemeralSequential() {
 +                return CreateBuilderImpl.this.withProtectedEphemeralSequential();
 +            }
 +            
 +            @Override
 +            public ACLCreateModePathAndBytesable<String> creatingParentsIfNeeded() {
 +                createParentsIfNeeded = true;
 +                return asACLCreateModePathAndBytesable();
 +            }
 +            
 +            @Override
 +            public ACLCreateModePathAndBytesable<String> creatingParentContainersIfNeeded() {
 +                setCreateParentsAsContainers();
 +                return asACLCreateModePathAndBytesable();
 +            }
 +        };
 +    }
 +    
 +    private ACLCreateModeStatBackgroundPathAndBytesable<String> asACLCreateModeStatBackgroundPathAndBytesable()
 +    {
 +        return new ACLCreateModeStatBackgroundPathAndBytesable<String>()
 +        {
 +            @Override
 +            public BackgroundPathAndBytesable<String> withACL(List<ACL> aclList) {
 +                return CreateBuilderImpl.this.withACL(aclList);
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground() {
++            public ErrorListenerPathAndBytesable<String> inBackground() {
 +                return CreateBuilderImpl.this.inBackground();
 +            }
 +
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context, Executor executor) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context, Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, context, executor);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Executor executor) {
 +                return CreateBuilderImpl.this.inBackground(callback, executor);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback, Object context) {
 +                return CreateBuilderImpl.this.inBackground(callback, context);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(BackgroundCallback callback) {
++            public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback callback) {
 +                return CreateBuilderImpl.this.inBackground(callback);
 +            }
 +            
 +            @Override
-             public PathAndBytesable<String> inBackground(Object context) {
++            public ErrorListenerPathAndBytesable<String> inBackground(Object context) {
 +                return CreateBuilderImpl.this.inBackground(context);
 +            }
 +
 +            @Override
 +            public String forPath(String path) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path);
 +            }
 +            
 +            @Override
 +            public String forPath(String path, byte[] data) throws Exception {
 +                return CreateBuilderImpl.this.forPath(path, data);
 +            }
 +
 +            @Override
 +            public ACLBackgroundPathAndBytesable<String> withMode(CreateMode mode) {
 +                return CreateBuilderImpl.this.withMode(mode);
 +            }
 +
 +            @Override
 +            public ACLCreateModeBackgroundPathAndBytesable<String> storingStatIn(Stat stat) {
 +                storingStat = stat;
 +                return CreateBuilderImpl.this;
 +            }            
 +        };
 +    }
  
      @VisibleForTesting
      volatile boolean debugForceFindProtectedNode = false;

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
index 577b0d6,0000000..528fe6f
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
@@@ -1,163 -1,0 +1,180 @@@
 +/**
 + * 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.curator.framework.imps;
 +
 +import com.google.common.base.Preconditions;
 +import com.google.common.collect.Lists;
 +import org.apache.curator.RetryLoop;
 +import org.apache.curator.TimeTrace;
- import org.apache.curator.framework.CuratorFramework;
 +import org.apache.curator.framework.api.BackgroundCallback;
 +import org.apache.curator.framework.api.CuratorEvent;
 +import org.apache.curator.framework.api.CuratorEventType;
++import org.apache.curator.framework.api.ErrorListenerMultiTransactionMain;
++import org.apache.curator.framework.api.UnhandledErrorListener;
 +import org.apache.curator.framework.api.transaction.CuratorMultiTransaction;
 +import org.apache.curator.framework.api.transaction.CuratorMultiTransactionMain;
 +import org.apache.curator.framework.api.transaction.CuratorOp;
 +import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
 +import org.apache.zookeeper.AsyncCallback;
 +import org.apache.zookeeper.OpResult;
 +import java.util.Arrays;
 +import java.util.List;
 +import java.util.concurrent.Callable;
 +import java.util.concurrent.Executor;
++import java.util.concurrent.ThreadFactory;
 +
 +public class CuratorMultiTransactionImpl implements
 +    CuratorMultiTransaction,
 +    CuratorMultiTransactionMain,
-     BackgroundOperation<CuratorMultiTransactionRecord>
++    BackgroundOperation<CuratorMultiTransactionRecord>,
++    ErrorListenerMultiTransactionMain
 +{
 +    private final CuratorFrameworkImpl client;
 +    private Backgrounding backgrounding = new Backgrounding();
 +
 +    public CuratorMultiTransactionImpl(CuratorFrameworkImpl client)
 +    {
 +        this.client = client;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground()
++    public ErrorListenerMultiTransactionMain inBackground()
 +    {
 +        backgrounding = new Backgrounding(true);
 +        return this;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground(Object context)
++    public ErrorListenerMultiTransactionMain inBackground(Object context)
 +    {
 +        backgrounding = new Backgrounding(context);
 +        return this;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground(BackgroundCallback callback)
++    public ErrorListenerMultiTransactionMain inBackground(BackgroundCallback callback)
 +    {
 +        backgrounding = new Backgrounding(callback);
 +        return this;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground(BackgroundCallback callback, Object context)
++    public ErrorListenerMultiTransactionMain inBackground(BackgroundCallback callback, Object context)
 +    {
 +        backgrounding = new Backgrounding(callback, context);
 +        return this;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground(BackgroundCallback callback, Executor executor)
++    public ErrorListenerMultiTransactionMain inBackground(BackgroundCallback callback, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(callback, executor);
 +        return this;
 +    }
 +
 +    @Override
-     public CuratorMultiTransactionMain inBackground(BackgroundCallback callback, Object context, Executor executor)
++    public ErrorListenerMultiTransactionMain inBackground(BackgroundCallback callback, Object context, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(client, callback, context, executor);
 +        return this;
 +    }
 +
 +    @Override
++    public CuratorMultiTransactionMain withUnhandledErrorListener(UnhandledErrorListener listener)
++    {
++        backgrounding = new Backgrounding(backgrounding, listener);
++        return this;
++    }
++
++    @Override
 +    public List<CuratorTransactionResult> forOperations(CuratorOp... operations) throws Exception
 +    {
 +        List<CuratorOp> ops = (operations != null) ? Arrays.asList(operations) : Lists.<CuratorOp>newArrayList();
 +        return forOperations(ops);
 +    }
 +
 +    @Override
 +    public List<CuratorTransactionResult> forOperations(List<CuratorOp> operations) throws Exception
 +    {
 +        operations = Preconditions.checkNotNull(operations, "operations cannot be null");
 +        Preconditions.checkArgument(!operations.isEmpty(), "operations list cannot be empty");
 +
 +        CuratorMultiTransactionRecord record = new CuratorMultiTransactionRecord();
 +        for ( CuratorOp curatorOp : operations )
 +        {
 +            record.add(curatorOp.get(), curatorOp.getTypeAndPath().getType(), curatorOp.getTypeAndPath().getForPath());
 +        }
 +
 +        if ( backgrounding.inBackground() )
 +        {
 +            client.processBackgroundOperation(new OperationAndData<>(this, record, backgrounding.getCallback(), null, backgrounding.getContext()), null);
 +            return null;
 +        }
 +        else
 +        {
 +            return forOperationsInForeground(record);
 +        }
 +    }
 +
 +    @Override
 +    public void performBackgroundOperation(final OperationAndData<CuratorMultiTransactionRecord> operationAndData) throws Exception
 +    {
-         final TimeTrace trace = client.getZookeeperClient().startTracer("CuratorMultiTransactionImpl-Background");
-         AsyncCallback.MultiCallback callback = new AsyncCallback.MultiCallback()
++        try
 +        {
-             @Override
-             public void processResult(int rc, String path, Object ctx, List<OpResult> opResults)
++            final TimeTrace trace = client.getZookeeperClient().startTracer("CuratorMultiTransactionImpl-Background");
++            AsyncCallback.MultiCallback callback = new AsyncCallback.MultiCallback()
 +            {
-                 trace.commit();
-                 List<CuratorTransactionResult> curatorResults = (opResults != null) ? CuratorTransactionImpl.wrapResults(client, opResults, operationAndData.getData()) : null;
-                 CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.TRANSACTION, rc, path, null, ctx, null, null, null, null, null, curatorResults);
-                 client.processBackgroundOperation(operationAndData, event);
-             }
-         };
-         client.getZooKeeper().multi(operationAndData.getData(), callback, backgrounding.getContext());
++                @Override
++                public void processResult(int rc, String path, Object ctx, List<OpResult> opResults)
++                {
++                    trace.commit();
++                    List<CuratorTransactionResult> curatorResults = (opResults != null) ? CuratorTransactionImpl.wrapResults(client, opResults, operationAndData.getData()) : null;
++                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.TRANSACTION, rc, path, null, ctx, null, null, null, null, null, curatorResults);
++                    client.processBackgroundOperation(operationAndData, event);
++                }
++            };
++            client.getZooKeeper().multi(operationAndData.getData(), callback, backgrounding.getContext());
++        }
++        catch ( Throwable e )
++        {
++            backgrounding.checkError(e);
++        }
 +    }
 +
 +    private List<CuratorTransactionResult> forOperationsInForeground(final CuratorMultiTransactionRecord record) throws Exception
 +    {
 +        TimeTrace trace = client.getZookeeperClient().startTracer("CuratorMultiTransactionImpl-Foreground");
 +        List<OpResult> responseData = RetryLoop.callWithRetry
 +        (
 +            client.getZookeeperClient(),
 +            new Callable<List<OpResult>>()
 +            {
 +                @Override
 +                public List<OpResult> call() throws Exception
 +                {
 +                    return client.getZooKeeper().multi(record);
 +                }
 +            }
 +        );
 +        trace.commit();
 +
 +        return CuratorTransactionImpl.wrapResults(client, responseData, record);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
index ab72308,833904b..21c5cd8
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
@@@ -20,15 -20,8 +20,7 @@@ package org.apache.curator.framework.im
  
  import org.apache.curator.RetryLoop;
  import org.apache.curator.TimeTrace;
- import org.apache.curator.framework.api.BackgroundCallback;
- import org.apache.curator.framework.api.BackgroundPathable;
- import org.apache.curator.framework.api.BackgroundVersionable;
- import org.apache.curator.framework.api.ChildrenDeletable;
- import org.apache.curator.framework.api.CuratorEvent;
- import org.apache.curator.framework.api.CuratorEventType;
- import org.apache.curator.framework.api.DeleteBuilder;
- import org.apache.curator.framework.api.DeleteBuilderMain;
- import org.apache.curator.framework.api.Pathable;
+ import org.apache.curator.framework.api.*;
 -import org.apache.curator.framework.api.transaction.CuratorTransactionBridge;
  import org.apache.curator.framework.api.transaction.OperationType;
  import org.apache.curator.framework.api.transaction.TransactionDeleteBuilder;
  import org.apache.curator.utils.ThreadUtils;
@@@ -150,36 -134,46 +142,50 @@@ class DeleteBuilderImpl implements Dele
      }
  
      @Override
+     public Pathable<Void> withUnhandledErrorListener(UnhandledErrorListener listener)
+     {
+         backgrounding = new Backgrounding(backgrounding, listener);
+         return this;
+     }
+ 
+     @Override
      public void performBackgroundOperation(final OperationAndData<String> operationAndData) throws Exception
      {
-         final TimeTrace trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Background");
-         client.getZooKeeper().delete
-             (
-                 operationAndData.getData(),
-                 version,
-                 new AsyncCallback.VoidCallback()
-                 {
-                     @Override
-                     public void processResult(int rc, String path, Object ctx)
+         try
+         {
+             final TimeTrace trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Background");
+             client.getZooKeeper().delete
+                 (
+                     operationAndData.getData(),
+                     version,
+                     new AsyncCallback.VoidCallback()
                      {
-                         trace.commit();
-                         if ( (rc == KeeperException.Code.NOTEMPTY.intValue()) && deletingChildrenIfNeeded )
-                         {
-                             backgroundDeleteChildrenThenNode(operationAndData);
-                         }
-                         else
+                         @Override
+                         public void processResult(int rc, String path, Object ctx)
                          {
-                             if ( (rc == KeeperException.Code.NONODE.intValue()) && quietly )
+                             trace.commit();
+                             if ( (rc == KeeperException.Code.NOTEMPTY.intValue()) && deletingChildrenIfNeeded )
                              {
-                                 rc = KeeperException.Code.OK.intValue();
+                                 backgroundDeleteChildrenThenNode(operationAndData);
+                             }
+                             else
+                             {
 -                                CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.DELETE, rc, path, null, ctx, null, null, null, null, null);
++                                if ( (rc == KeeperException.Code.NONODE.intValue()) && quietly )
++                                {
++                                    rc = KeeperException.Code.OK.intValue();
++                                }
++                                CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.DELETE, rc, path, null, ctx, null, null, null, null, null, null);
+                                 client.processBackgroundOperation(operationAndData, event);
                              }
-                             CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.DELETE, rc, path, null, ctx, null, null, null, null, null, null);
-                             client.processBackgroundOperation(operationAndData, event);
                          }
-                     }
-                 },
-                 backgrounding.getContext()
-             );
+                     },
+                     backgrounding.getContext()
+                 );
+         }
+         catch ( Throwable e )
+         {
+             backgrounding.checkError(e);
+         }
      }
  
      private void backgroundDeleteChildrenThenNode(final OperationAndData<String> mainOperationAndData)

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
index 4b3d214,5fb7056..7f55cf7
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
@@@ -122,26 -115,40 +115,40 @@@ class ExistsBuilderImpl implements Exis
      }
  
      @Override
+     public Pathable<Stat> withUnhandledErrorListener(UnhandledErrorListener listener)
+     {
+         backgrounding = new Backgrounding(backgrounding, listener);
+         return this;
+     }
+ 
+     @Override
      public void performBackgroundOperation(final OperationAndData<String> operationAndData) throws Exception
      {
-         final TimeTrace   trace = client.getZookeeperClient().startTracer("ExistsBuilderImpl-Background");
-         AsyncCallback.StatCallback callback = new AsyncCallback.StatCallback()
+         try
          {
-             @Override
-             public void processResult(int rc, String path, Object ctx, Stat stat)
+             final TimeTrace   trace = client.getZookeeperClient().startTracer("ExistsBuilderImpl-Background");
+             AsyncCallback.StatCallback callback = new AsyncCallback.StatCallback()
              {
-                 trace.commit();
-                 CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.EXISTS, rc, path, null, ctx, stat, null, null, null, null, null);
-                 client.processBackgroundOperation(operationAndData, event);
+                 @Override
+                 public void processResult(int rc, String path, Object ctx, Stat stat)
+                 {
+                     trace.commit();
 -                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.EXISTS, rc, path, null, ctx, stat, null, null, null, null);
++                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.EXISTS, rc, path, null, ctx, stat, null, null, null, null, null);
+                     client.processBackgroundOperation(operationAndData, event);
+                 }
+             };
+             if ( watching.isWatched() )
+             {
+                 client.getZooKeeper().exists(operationAndData.getData(), true, callback, backgrounding.getContext());
+             }
+             else
+             {
 -                client.getZooKeeper().exists(operationAndData.getData(), watching.getWatcher(), callback, backgrounding.getContext());
++                client.getZooKeeper().exists(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
              }
-         };
-         if ( watching.isWatched() )
-         {
-             client.getZooKeeper().exists(operationAndData.getData(), true, callback, backgrounding.getContext());
          }
-         else
+         catch ( Throwable e )
          {
-             client.getZooKeeper().exists(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
+             backgrounding.checkError(e);
          }
      }
  

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/GetACLBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/GetACLBuilderImpl.java
index f65c933,351a8c5..fa02740
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetACLBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetACLBuilderImpl.java
@@@ -97,18 -106,25 +106,25 @@@ class GetACLBuilderImpl implements GetA
      @Override
      public void performBackgroundOperation(final OperationAndData<String> operationAndData) throws Exception
      {
-         final TimeTrace             trace = client.getZookeeperClient().startTracer("GetACLBuilderImpl-Background");
-         AsyncCallback.ACLCallback   callback = new AsyncCallback.ACLCallback()
+         try
          {
-             @Override
-             public void processResult(int rc, String path, Object ctx, List<ACL> acl, Stat stat)
+             final TimeTrace             trace = client.getZookeeperClient().startTracer("GetACLBuilderImpl-Background");
+             AsyncCallback.ACLCallback   callback = new AsyncCallback.ACLCallback()
              {
-                 trace.commit();
-                 CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.GET_ACL, rc, path, null, ctx, stat, null, null, null, acl, null);
-                 client.processBackgroundOperation(operationAndData, event);
-             }
-         };
-         client.getZooKeeper().getACL(operationAndData.getData(), responseStat, callback, backgrounding.getContext());
+                 @Override
+                 public void processResult(int rc, String path, Object ctx, List<ACL> acl, Stat stat)
+                 {
+                     trace.commit();
 -                    CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.GET_ACL, rc, path, null, ctx, stat, null, null, null, acl);
++                    CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.GET_ACL, rc, path, null, ctx, stat, null, null, null, acl, null);
+                     client.processBackgroundOperation(operationAndData, event);
+                 }
+             };
+             client.getZooKeeper().getACL(operationAndData.getData(), responseStat, callback, backgrounding.getContext());
+         }
+         catch ( Throwable e )
+         {
+             backgrounding.checkError(e);
+         }
      }
  
      @Override

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
index 8365585,745800d..bc9cfc6
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
@@@ -151,28 -160,35 +160,35 @@@ class GetChildrenBuilderImpl implement
      @Override
      public void performBackgroundOperation(final OperationAndData<String> operationAndData) throws Exception
      {
-         final TimeTrace       trace = client.getZookeeperClient().startTracer("GetChildrenBuilderImpl-Background");
-         AsyncCallback.Children2Callback callback = new AsyncCallback.Children2Callback()
+         try
          {
-             @Override
-             public void processResult(int rc, String path, Object o, List<String> strings, Stat stat)
+             final TimeTrace       trace = client.getZookeeperClient().startTracer("GetChildrenBuilderImpl-Background");
+             AsyncCallback.Children2Callback callback = new AsyncCallback.Children2Callback()
              {
-                 trace.commit();
-                 if ( strings == null )
+                 @Override
+                 public void processResult(int rc, String path, Object o, List<String> strings, Stat stat)
                  {
-                     strings = Lists.newArrayList();
+                     trace.commit();
+                     if ( strings == null )
+                     {
+                         strings = Lists.newArrayList();
+                     }
 -                    CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.CHILDREN, rc, path, null, o, stat, null, strings, null, null);
++                    CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.CHILDREN, rc, path, null, o, stat, null, strings, null, null, null);
+                     client.processBackgroundOperation(operationAndData, event);
                  }
-                 CuratorEventImpl event = new CuratorEventImpl(client, CuratorEventType.CHILDREN, rc, path, null, o, stat, null, strings, null, null, null);
-                 client.processBackgroundOperation(operationAndData, event);
+             };
+             if ( watching.isWatched() )
+             {
+                 client.getZooKeeper().getChildren(operationAndData.getData(), true, callback, backgrounding.getContext());
+             }
+             else
+             {
 -                client.getZooKeeper().getChildren(operationAndData.getData(), watching.getWatcher(), callback, backgrounding.getContext());
++                client.getZooKeeper().getChildren(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
              }
-         };
-         if ( watching.isWatched() )
-         {
-             client.getZooKeeper().getChildren(operationAndData.getData(), true, callback, backgrounding.getContext());
          }
-         else
+         catch ( Throwable e )
          {
-             client.getZooKeeper().getChildren(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
+             backgrounding.checkError(e);
          }
      }
  

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
index b64f38e,0000000..2ba4d71
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
@@@ -1,295 -1,0 +1,302 @@@
 +/**
 + * 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.curator.framework.imps;
 +
 +import org.apache.curator.RetryLoop;
 +import org.apache.curator.TimeTrace;
- import org.apache.curator.framework.api.BackgroundCallback;
- import org.apache.curator.framework.api.BackgroundEnsembleable;
- import org.apache.curator.framework.api.CuratorEvent;
- import org.apache.curator.framework.api.CuratorEventType;
- import org.apache.curator.framework.api.CuratorWatcher;
- import org.apache.curator.framework.api.Ensembleable;
- import org.apache.curator.framework.api.GetConfigBuilder;
- import org.apache.curator.framework.api.WatchBackgroundEnsembleable;
++import org.apache.curator.framework.api.*;
 +import org.apache.zookeeper.AsyncCallback;
 +import org.apache.zookeeper.Watcher;
 +import org.apache.zookeeper.ZooDefs;
 +import org.apache.zookeeper.data.Stat;
 +import java.util.concurrent.Callable;
 +import java.util.concurrent.Executor;
 +
- public class GetConfigBuilderImpl implements GetConfigBuilder, BackgroundOperation<Void>
++public class GetConfigBuilderImpl implements GetConfigBuilder, BackgroundOperation<Void>, ErrorListenerEnsembleable<byte[]>
 +{
 +    private final CuratorFrameworkImpl client;
 +
 +    private Backgrounding backgrounding;
 +    private Watching watching;
 +    private Stat stat;
 +
 +    public GetConfigBuilderImpl(CuratorFrameworkImpl client)
 +    {
 +        this.client = client;
 +        backgrounding = new Backgrounding();
 +        watching = new Watching();
 +    }
 +
 +    @Override
 +    public WatchBackgroundEnsembleable<byte[]> storingStatIn(Stat stat)
 +    {
 +        this.stat = stat;
 +        return new WatchBackgroundEnsembleable<byte[]>()
 +        {
 +            @Override
-             public Ensembleable<byte[]> inBackground()
++            public ErrorListenerEnsembleable<byte[]> inBackground()
 +            {
 +                return GetConfigBuilderImpl.this.inBackground();
 +            }
 +
 +            @Override
-             public Ensembleable<byte[]> inBackground(Object context)
++            public ErrorListenerEnsembleable<byte[]> inBackground(Object context)
 +            {
 +                return GetConfigBuilderImpl.this.inBackground(context);
 +            }
 +
 +            @Override
-             public Ensembleable<byte[]> inBackground(BackgroundCallback callback)
++            public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback)
 +            {
 +                return GetConfigBuilderImpl.this.inBackground(callback);
 +            }
 +
 +            @Override
-             public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
++            public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
 +            {
 +                return GetConfigBuilderImpl.this.inBackground(callback, context);
 +            }
 +
 +            @Override
-             public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
++            public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
 +            {
 +                return GetConfigBuilderImpl.this.inBackground(callback, executor);
 +            }
 +
 +            @Override
-             public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
++            public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
 +            {
 +                return GetConfigBuilderImpl.this.inBackground(callback, context, executor);
 +            }
 +
 +            @Override
 +            public byte[] forEnsemble() throws Exception
 +            {
 +                return GetConfigBuilderImpl.this.forEnsemble();
 +            }
 +
 +            @Override
 +            public BackgroundEnsembleable<byte[]> watched()
 +            {
 +                return GetConfigBuilderImpl.this.watched();
 +            }
 +
 +            @Override
 +            public BackgroundEnsembleable<byte[]> usingWatcher(Watcher watcher)
 +            {
 +                return GetConfigBuilderImpl.this.usingWatcher(watcher);
 +            }
 +
 +            @Override
 +            public BackgroundEnsembleable<byte[]> usingWatcher(CuratorWatcher watcher)
 +            {
 +                return GetConfigBuilderImpl.this.usingWatcher(watcher);
 +            }
 +        };
 +    }
 +
 +    @Override
 +    public BackgroundEnsembleable<byte[]> watched()
 +    {
 +        watching = new Watching(true);
 +        return new InternalBackgroundEnsembleable();
 +    }
 +
 +    @Override
 +    public BackgroundEnsembleable<byte[]> usingWatcher(Watcher watcher)
 +    {
 +        watching = new Watching(watcher);
 +        return new InternalBackgroundEnsembleable();
 +    }
 +
 +    @Override
 +    public BackgroundEnsembleable<byte[]> usingWatcher(CuratorWatcher watcher)
 +    {
 +        watching = new Watching(watcher);
 +        return new InternalBackgroundEnsembleable();
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground()
++    public ErrorListenerEnsembleable<byte[]> inBackground()
 +    {
 +        backgrounding = new Backgrounding(true);
 +        return this;
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground(Object context)
++    public ErrorListenerEnsembleable<byte[]> inBackground(Object context)
 +    {
 +        backgrounding = new Backgrounding(context);
 +        return this;
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground(BackgroundCallback callback)
++    public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback)
 +    {
 +        backgrounding = new Backgrounding(callback);
 +        return this;
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
++    public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
 +    {
 +        backgrounding = new Backgrounding(callback, context);
 +        return this;
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
++    public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(callback, executor);
 +        return this;
 +    }
 +
 +    @Override
-     public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
++    public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(client, callback, context, executor);
 +        return this;
 +    }
 +
 +    @Override
++    public Ensembleable<byte[]> withUnhandledErrorListener(UnhandledErrorListener listener)
++    {
++        backgrounding = new Backgrounding(backgrounding, listener);
++        return this;
++    }
++
++    @Override
 +    public byte[] forEnsemble() throws Exception
 +    {
 +        if ( backgrounding.inBackground() )
 +        {
 +            client.processBackgroundOperation(new OperationAndData<Void>(this, null, backgrounding.getCallback(), null, backgrounding.getContext()), null);
 +            return null;
 +        }
 +        else
 +        {
 +            return configInForeground();
 +        }
 +    }
 +
 +    @Override
 +    public void performBackgroundOperation(final OperationAndData<Void> operationAndData) throws Exception
 +    {
-         final TimeTrace trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background");
-         AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
++        try
 +        {
-             @Override
-             public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
++            final TimeTrace trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background");
++            AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
 +            {
-                 trace.commit();
-                 CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_CONFIG, rc, path, null, ctx, stat, data, null, null, null, null);
-                 client.processBackgroundOperation(operationAndData, event);
++                @Override
++                public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
++                {
++                    trace.commit();
++                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_CONFIG, rc, path, null, ctx, stat, data, null, null, null, null);
++                    client.processBackgroundOperation(operationAndData, event);
++                }
++            };
++            if ( watching.isWatched() )
++            {
++                client.getZooKeeper().getConfig(true, callback, backgrounding.getContext());
++            }
++            else
++            {
++                client.getZooKeeper().getConfig(watching.getWatcher(client, ZooDefs.CONFIG_NODE), callback, backgrounding.getContext());
 +            }
-         };
-         if ( watching.isWatched() )
-         {
-             client.getZooKeeper().getConfig(true, callback, backgrounding.getContext());
 +        }
-         else
++        catch ( Throwable e )
 +        {
-             client.getZooKeeper().getConfig(watching.getWatcher(client, ZooDefs.CONFIG_NODE), callback, backgrounding.getContext());
++            backgrounding.checkError(e);
 +        }
 +    }
 +
 +    private byte[] configInForeground() throws Exception
 +    {
 +        TimeTrace trace = client.getZookeeperClient().startTracer("GetConfigBuilderImpl-Foreground");
 +        try
 +        {
 +            return RetryLoop.callWithRetry
 +            (
 +                client.getZookeeperClient(),
 +                new Callable<byte[]>()
 +                {
 +                    @Override
 +                    public byte[] call() throws Exception
 +                    {
 +                        if ( watching.isWatched() )
 +                        {
 +                            return client.getZooKeeper().getConfig(true, stat);
 +                        }
 +                        return client.getZooKeeper().getConfig(watching.getWatcher(client, ZooDefs.CONFIG_NODE), stat);
 +                    }
 +                }
 +            );
 +        }
 +        finally
 +        {
 +            trace.commit();
 +        }
 +    }
 +
 +    private class InternalBackgroundEnsembleable implements BackgroundEnsembleable<byte[]>
 +    {
 +        @Override
-         public Ensembleable<byte[]> inBackground()
++        public ErrorListenerEnsembleable<byte[]> inBackground()
 +        {
 +            return GetConfigBuilderImpl.this.inBackground();
 +        }
 +
 +        @Override
-         public Ensembleable<byte[]> inBackground(Object context)
++        public ErrorListenerEnsembleable<byte[]> inBackground(Object context)
 +        {
 +            return GetConfigBuilderImpl.this.inBackground(context);
 +        }
 +
 +        @Override
-         public Ensembleable<byte[]> inBackground(BackgroundCallback callback)
++        public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback)
 +        {
 +            return GetConfigBuilderImpl.this.inBackground(callback);
 +        }
 +
 +        @Override
-         public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
++        public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
 +        {
 +            return GetConfigBuilderImpl.this.inBackground(callback, context);
 +        }
 +
 +        @Override
-         public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
++        public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
 +        {
 +            return GetConfigBuilderImpl.this.inBackground(callback, executor);
 +        }
 +
 +        @Override
-         public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
++        public ErrorListenerEnsembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
 +        {
 +            return GetConfigBuilderImpl.this.inBackground(callback, context, executor);
 +        }
 +
 +        @Override
 +        public byte[] forEnsemble() throws Exception
 +        {
 +            return GetConfigBuilderImpl.this.forEnsemble();
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
index e2aa053,94d27ad..72103b9
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
@@@ -232,37 -231,44 +231,44 @@@ class GetDataBuilderImpl implements Get
      @Override
      public void performBackgroundOperation(final OperationAndData<String> operationAndData) throws Exception
      {
-         final TimeTrace   trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background");
-         AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
+         try
          {
-             @Override
-             public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
+             final TimeTrace   trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background");
+             AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
              {
-                 trace.commit();
-                 if ( decompress && (data != null) )
+                 @Override
+                 public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
                  {
-                     try
-                     {
-                         data = client.getCompressionProvider().decompress(path, data);
-                     }
-                     catch ( Exception e )
+                     trace.commit();
+                     if ( decompress && (data != null) )
                      {
-                         ThreadUtils.checkInterrupted(e);
-                         log.error("Decompressing for path: " + path, e);
-                         rc = KeeperException.Code.DATAINCONSISTENCY.intValue();
+                         try
+                         {
+                             data = client.getCompressionProvider().decompress(path, data);
+                         }
+                         catch ( Exception e )
+                         {
+                             ThreadUtils.checkInterrupted(e);
+                             log.error("Decompressing for path: " + path, e);
+                             rc = KeeperException.Code.DATAINCONSISTENCY.intValue();
+                         }
                      }
 -                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_DATA, rc, path, null, ctx, stat, data, null, null, null);
++                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_DATA, rc, path, null, ctx, stat, data, null, null, null, null);
+                     client.processBackgroundOperation(operationAndData, event);
                  }
-                 CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_DATA, rc, path, null, ctx, stat, data, null, null, null, null);
-                 client.processBackgroundOperation(operationAndData, event);
+             };
+             if ( watching.isWatched() )
+             {
+                 client.getZooKeeper().getData(operationAndData.getData(), true, callback, backgrounding.getContext());
+             }
+             else
+             {
 -                client.getZooKeeper().getData(operationAndData.getData(), watching.getWatcher(), callback, backgrounding.getContext());
++                client.getZooKeeper().getData(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
              }
-         };
-         if ( watching.isWatched() )
-         {
-             client.getZooKeeper().getData(operationAndData.getData(), true, callback, backgrounding.getContext());
          }
-         else
+         catch ( Throwable e )
          {
-             client.getZooKeeper().getData(operationAndData.getData(), watching.getWatcher(client, operationAndData.getData()), callback, backgrounding.getContext());
+             backgrounding.checkError(e);
          }
      }
  

http://git-wip-us.apache.org/repos/asf/curator/blob/062a7d75/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java
index e786883,0000000..74683de
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java
@@@ -1,272 -1,0 +1,286 @@@
 +/**
 + * 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.curator.framework.imps;
 +
 +import com.google.common.collect.ImmutableList;
 +import org.apache.curator.RetryLoop;
 +import org.apache.curator.TimeTrace;
 +import org.apache.curator.framework.api.*;
 +import org.apache.zookeeper.AsyncCallback;
 +import org.apache.zookeeper.data.Stat;
 +import org.apache.zookeeper.server.DataTree;
 +import java.util.Arrays;
 +import java.util.List;
 +import java.util.concurrent.Callable;
 +import java.util.concurrent.Executor;
 +
- public class ReconfigBuilderImpl implements ReconfigBuilder, BackgroundOperation<Void>
++public class ReconfigBuilderImpl implements ReconfigBuilder, BackgroundOperation<Void>, ErrorListenerReconfigBuilderMain
 +{
 +    private final CuratorFrameworkImpl client;
 +
 +    private Backgrounding backgrounding = new Backgrounding();
 +    private Stat responseStat;
 +    private long fromConfig = -1;
 +    private List<String> newMembers;
 +    private List<String> joining;
 +    private List<String> leaving;
 +
 +    public ReconfigBuilderImpl(CuratorFrameworkImpl client)
 +    {
 +        this.client = client;
 +    }
 +
 +    private byte[] forEnsemble() throws Exception
 +    {
 +        if ( backgrounding.inBackground() )
 +        {
 +            client.processBackgroundOperation(new OperationAndData<>(this, null, backgrounding.getCallback(), null, backgrounding.getContext()), null);
 +            return new byte[0];
 +        }
 +        else
 +        {
 +            return ensembleInForeground();
 +        }
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground()
++    public ErrorListenerReconfigBuilderMain inBackground()
 +    {
 +        backgrounding = new Backgrounding(true);
 +        return this;
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground(Object context)
++    public ErrorListenerReconfigBuilderMain inBackground(Object context)
 +    {
 +        backgrounding = new Backgrounding(context);
 +        return this;
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground(BackgroundCallback callback)
++    public ErrorListenerReconfigBuilderMain inBackground(BackgroundCallback callback)
 +    {
 +        backgrounding = new Backgrounding(callback);
 +        return this;
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground(BackgroundCallback callback, Object context)
++    public ErrorListenerReconfigBuilderMain inBackground(BackgroundCallback callback, Object context)
 +    {
 +        backgrounding = new Backgrounding(callback, context);
 +        return this;
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground(BackgroundCallback callback, Executor executor)
++    public ErrorListenerReconfigBuilderMain inBackground(BackgroundCallback callback, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(callback, executor);
 +        return this;
 +    }
 +
 +    @Override
-     public ReconfigBuilderMain inBackground(BackgroundCallback callback, Object context, Executor executor)
++    public ErrorListenerReconfigBuilderMain inBackground(BackgroundCallback callback, Object context, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(client, callback, context, executor);
 +        return this;
 +    }
 +
 +    @Override
++    public ReconfigBuilderMain withUnhandledErrorListener(UnhandledErrorListener listener)
++    {
++        backgrounding = new Backgrounding(backgrounding, listener);
++        return this;
++    }
++
++    @Override
 +    public StatConfigureEnsembleable withNewMembers(String... server)
 +    {
 +        return withNewMembers((server != null) ? Arrays.asList(server) : null);
 +    }
 +
 +    @Override
 +    public StatConfigureEnsembleable withNewMembers(List<String> servers)
 +    {
 +        newMembers = (servers != null) ? ImmutableList.copyOf(servers) : ImmutableList.<String>of();
 +        return new StatConfigureEnsembleable()
 +        {
 +            @Override
 +            public Ensembleable<byte[]> fromConfig(long config) throws Exception
 +            {
 +                fromConfig = config;
 +                return this;
 +            }
 +
 +            @Override
 +            public byte[] forEnsemble() throws Exception
 +            {
 +                return ReconfigBuilderImpl.this.forEnsemble();
 +            }
 +
 +            @Override
 +            public ConfigureEnsembleable storingStatIn(Stat stat)
 +            {
 +                responseStat = stat;
 +                return this;
 +            }
 +        };
 +    }
 +
 +    @Override
 +    public LeaveStatConfigEnsembleable joining(String... server)
 +    {
 +        return joining((server != null) ? Arrays.asList(server) : null);
 +    }
 +
 +    @Override
 +    public LeaveStatConfigEnsembleable joining(List<String> servers)
 +    {
 +        joining = (servers != null) ? ImmutableList.copyOf(servers) : ImmutableList.<String>of();
 +
 +        return new LeaveStatConfigEnsembleable()
 +        {
 +            @Override
 +            public byte[] forEnsemble() throws Exception
 +            {
 +                return ReconfigBuilderImpl.this.forEnsemble();
 +            }
 +
 +            @Override
 +            public ConfigureEnsembleable storingStatIn(Stat stat)
 +            {
 +                responseStat = stat;
 +                return this;
 +            }
 +
 +            @Override
 +            public Ensembleable<byte[]> fromConfig(long config) throws Exception
 +            {
 +                fromConfig = config;
 +                return this;
 +            }
 +
 +            @Override
 +            public JoinStatConfigEnsembleable leaving(String... server)
 +            {
 +                return ReconfigBuilderImpl.this.leaving(server);
 +            }
 +
 +            @Override
 +            public JoinStatConfigEnsembleable leaving(List<String> servers)
 +            {
 +                return ReconfigBuilderImpl.this.leaving(servers);
 +            }
 +        };
 +    }
 +
 +    @Override
 +    public JoinStatConfigEnsembleable leaving(String... server)
 +    {
 +        return leaving((server != null) ? Arrays.asList(server) : null);
 +    }
 +
 +    @Override
 +    public JoinStatConfigEnsembleable leaving(List<String> servers)
 +    {
 +        leaving = (servers != null) ? ImmutableList.copyOf(servers) : ImmutableList.<String>of();
 +
 +        return new JoinStatConfigEnsembleable()
 +        {
 +            @Override
 +            public byte[] forEnsemble() throws Exception
 +            {
 +                return ReconfigBuilderImpl.this.forEnsemble();
 +            }
 +
 +            @Override
 +            public ConfigureEnsembleable storingStatIn(Stat stat)
 +            {
 +                responseStat = stat;
 +                return this;
 +            }
 +
 +            @Override
 +            public Ensembleable<byte[]> fromConfig(long config) throws Exception
 +            {
 +                fromConfig = config;
 +                return this;
 +            }
 +
 +            @Override
 +            public LeaveStatConfigEnsembleable joining(String... server)
 +            {
 +                return joining((server != null) ? Arrays.asList(server) : null);
 +            }
 +
 +            @Override
 +            public LeaveStatConfigEnsembleable joining(List<String> servers)
 +            {
 +                return ReconfigBuilderImpl.this.joining(servers);
 +            }
 +        };
 +    }
 +
 +    @Override
 +    public void performBackgroundOperation(final OperationAndData<Void> data) throws Exception
 +    {
-         final TimeTrace trace = client.getZookeeperClient().startTracer("ReconfigBuilderImpl-Background");
-         AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
++        try
 +        {
-             @Override
-             public void processResult(int rc, String path, Object ctx, byte[] bytes, Stat stat)
++            final TimeTrace trace = client.getZookeeperClient().startTracer("ReconfigBuilderImpl-Background");
++            AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
 +            {
-                 trace.commit();
-                 if ( (responseStat != null) && (stat != null) )
++                @Override
++                public void processResult(int rc, String path, Object ctx, byte[] bytes, Stat stat)
 +                {
-                     DataTree.copyStat(stat, responseStat);
++                    trace.commit();
++                    if ( (responseStat != null) && (stat != null) )
++                    {
++                        DataTree.copyStat(stat, responseStat);
++                    }
++                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.RECONFIG, rc, path, null, ctx, stat, bytes, null, null, null, null);
++                    client.processBackgroundOperation(data, event);
 +                }
-                 CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.RECONFIG, rc, path, null, ctx, stat, bytes, null, null, null, null);
-                 client.processBackgroundOperation(data, event);
-             }
-         };
-         client.getZooKeeper().reconfig(joining, leaving, newMembers, fromConfig, callback, backgrounding.getContext());
++            };
++            client.getZooKeeper().reconfig(joining, leaving, newMembers, fromConfig, callback, backgrounding.getContext());
++        }
++        catch ( Throwable e )
++        {
++            backgrounding.checkError(e);
++        }
 +    }
 +
 +    private byte[] ensembleInForeground() throws Exception
 +    {
 +        TimeTrace trace = client.getZookeeperClient().startTracer("ReconfigBuilderImpl-Foreground");
 +        byte[] responseData = RetryLoop.callWithRetry
 +            (
 +                client.getZookeeperClient(),
 +                new Callable<byte[]>()
 +                {
 +                    @Override
 +                    public byte[] call() throws Exception
 +                    {
 +                        return client.getZooKeeper().reconfig(joining, leaving, newMembers, fromConfig, responseStat);
 +                    }
 +                }
 +            );
 +        trace.commit();
 +        return responseData;
 +    }
 +}