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 2014/06/07 20:19:19 UTC

[21/50] [abbrv] git commit: started work on service discovery

started work on service discovery


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

Branch: refs/heads/master
Commit: 87582a9b2f5640fedaa6122a8c7c7d4eafb96e19
Parents: c6229cf
Author: randgalt <ra...@apache.org>
Authored: Fri May 30 17:14:45 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Fri May 30 17:14:45 2014 -0500

----------------------------------------------------------------------
 curator-x-rpc/pom.xml                           |   19 +
 .../curator/x/rpc/CuratorProjectionServer.java  |    6 +-
 .../curator/x/rpc/connections/CuratorEntry.java |    8 +
 .../x/rpc/idl/discovery/DiscoveryInstance.java  |   66 +
 .../idl/discovery/DiscoveryInstanceType.java    |    8 +
 .../rpc/idl/discovery/DiscoveryProjection.java  |   38 +
 .../discovery/DiscoveryProviderProjection.java  |   38 +
 .../x/rpc/idl/discovery/DiscoveryService.java   |  211 +
 .../idl/discovery/DiscoveryServiceLowLevel.java |   85 +
 .../rpc/idl/discovery/ProviderStrategyType.java |    9 +
 .../idl/services/CuratorProjectionService.java  |   18 +-
 .../x/rpc/idl/structs/CuratorProjection.java    |    1 -
 curator-x-rpc/src/main/scripts/generate.sh      |    3 +-
 curator-x-rpc/src/main/thrift/curator.thrift    |   44 +-
 .../curator/generated/CuratorService.java       |  133 +-
 .../curator/generated/DiscoveryInstance.java    | 1201 ++++
 .../generated/DiscoveryInstanceType.java        |   48 +
 .../curator/generated/DiscoveryProjection.java  |  388 ++
 .../generated/DiscoveryProviderProjection.java  |  388 ++
 .../curator/generated/DiscoveryService.java     | 6059 ++++++++++++++++++
 .../generated/DiscoveryServiceLowLevel.java     | 3339 ++++++++++
 .../curator/generated/ProviderStrategyType.java |   51 +
 22 files changed, 12135 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-rpc/pom.xml b/curator-x-rpc/pom.xml
index 6aeaa94..3f13a81 100644
--- a/curator-x-rpc/pom.xml
+++ b/curator-x-rpc/pom.xml
@@ -31,6 +31,25 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-x-discovery</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>log4j-over-slf4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
             <groupId>com.facebook.swift</groupId>
             <artifactId>swift-service</artifactId>
             <exclusions>

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/CuratorProjectionServer.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/CuratorProjectionServer.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/CuratorProjectionServer.java
index 78f8eaa..a0f7817 100644
--- a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/CuratorProjectionServer.java
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/CuratorProjectionServer.java
@@ -30,6 +30,8 @@ import com.google.common.io.Resources;
 import org.apache.curator.x.rpc.configuration.Configuration;
 import org.apache.curator.x.rpc.configuration.ConfigurationBuilder;
 import org.apache.curator.x.rpc.connections.ConnectionManager;
+import org.apache.curator.x.rpc.idl.discovery.DiscoveryService;
+import org.apache.curator.x.rpc.idl.discovery.DiscoveryServiceLowLevel;
 import org.apache.curator.x.rpc.idl.services.EventService;
 import org.apache.curator.x.rpc.idl.services.CuratorProjectionService;
 import org.slf4j.Logger;
@@ -97,8 +99,10 @@ public class CuratorProjectionServer
         this.configuration = configuration;
         connectionManager = new ConnectionManager(configuration.getConnections(), configuration.getProjectionExpiration().toMillis());
         EventService eventService = new EventService(connectionManager, configuration.getPingTime().toMillis());
+        DiscoveryService discoveryService = new DiscoveryService(connectionManager);
         CuratorProjectionService projectionService = new CuratorProjectionService(connectionManager);
-        ThriftServiceProcessor processor = new ThriftServiceProcessor(new ThriftCodecManager(), Lists.<ThriftEventHandler>newArrayList(), projectionService, eventService);
+        DiscoveryServiceLowLevel discoveryServiceLowLevel = new DiscoveryServiceLowLevel(connectionManager);
+        ThriftServiceProcessor processor = new ThriftServiceProcessor(new ThriftCodecManager(), Lists.<ThriftEventHandler>newArrayList(), projectionService, eventService, discoveryService, discoveryServiceLowLevel);
         server = new ThriftServer(processor, configuration.getThrift());
     }
 

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/connections/CuratorEntry.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/connections/CuratorEntry.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/connections/CuratorEntry.java
index 9e57c6f..d157c27 100644
--- a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/connections/CuratorEntry.java
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/connections/CuratorEntry.java
@@ -1,5 +1,6 @@
 package org.apache.curator.x.rpc.connections;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Queues;
 import org.apache.curator.framework.CuratorFramework;
@@ -25,6 +26,13 @@ public class CuratorEntry implements Closeable
     private final AtomicReference<State> state = new AtomicReference<State>(State.OPEN);
     private final Map<String, Entry> things = Maps.newConcurrentMap();
 
+    public static <T> T mustGetThing(CuratorEntry entry, String id, Class<T> clazz)
+    {
+        T thing = entry.getThing(id, clazz);
+        Preconditions.checkNotNull(thing, "No item of type " + clazz.getSimpleName() + " found with id " + id);
+        return thing;
+    }
+
     private static class Entry
     {
         final Object thing;

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstance.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstance.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstance.java
new file mode 100644
index 0000000..94e6307
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstance.java
@@ -0,0 +1,66 @@
+package org.apache.curator.x.rpc.idl.discovery;
+
+import com.facebook.swift.codec.ThriftField;
+import com.facebook.swift.codec.ThriftStruct;
+import org.apache.curator.x.discovery.ServiceInstance;
+
+@ThriftStruct
+public class DiscoveryInstance
+{
+    @ThriftField(1)
+    public String name;
+
+    @ThriftField(2)
+    public String id;
+
+    @ThriftField(3)
+    public String address;
+
+    @ThriftField(4)
+    public Integer port;
+
+    @ThriftField(5)
+    public Integer sslPort;
+
+    @ThriftField(6)
+    public byte[] payload;
+
+    @ThriftField(7)
+    public long registrationTimeUTC;
+
+    @ThriftField(8)
+    public DiscoveryInstanceType serviceType;
+
+    @ThriftField(9)
+    public String uriSpec;
+
+    public DiscoveryInstance()
+    {
+    }
+
+    public DiscoveryInstance(ServiceInstance<byte[]> instance)
+    {
+        this.name = instance.getName();
+        this.id = instance.getId();
+        this.address = instance.getAddress();
+        this.port = instance.getPort();
+        this.sslPort = instance.getSslPort();
+        this.payload = instance.getPayload();
+        this.registrationTimeUTC = instance.getRegistrationTimeUTC();
+        this.serviceType = DiscoveryInstanceType.valueOf(instance.getServiceType().name());
+        this.uriSpec = instance.buildUriSpec();
+    }
+
+    public DiscoveryInstance(String name, String id, String address, Integer port, Integer sslPort, byte[] payload, long registrationTimeUTC, DiscoveryInstanceType serviceType, String uriSpec)
+    {
+        this.name = name;
+        this.id = id;
+        this.address = address;
+        this.port = port;
+        this.sslPort = sslPort;
+        this.payload = payload;
+        this.registrationTimeUTC = registrationTimeUTC;
+        this.serviceType = serviceType;
+        this.uriSpec = uriSpec;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstanceType.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstanceType.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstanceType.java
new file mode 100644
index 0000000..ac7cc5d
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryInstanceType.java
@@ -0,0 +1,8 @@
+package org.apache.curator.x.rpc.idl.discovery;
+
+public enum DiscoveryInstanceType
+{
+    DYNAMIC,
+    STATIC,
+    PERMANENT
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProjection.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProjection.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProjection.java
new file mode 100644
index 0000000..6b1e0f4
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProjection.java
@@ -0,0 +1,38 @@
+/**
+ * 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.x.rpc.idl.discovery;
+
+import com.facebook.swift.codec.ThriftField;
+import com.facebook.swift.codec.ThriftStruct;
+
+@ThriftStruct
+public class DiscoveryProjection
+{
+    @ThriftField(1)
+    public String id;
+
+    public DiscoveryProjection()
+    {
+    }
+
+    public DiscoveryProjection(String id)
+    {
+        this.id = id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProviderProjection.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProviderProjection.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProviderProjection.java
new file mode 100644
index 0000000..c8655fa
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryProviderProjection.java
@@ -0,0 +1,38 @@
+/**
+ * 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.x.rpc.idl.discovery;
+
+import com.facebook.swift.codec.ThriftField;
+import com.facebook.swift.codec.ThriftStruct;
+
+@ThriftStruct
+public class DiscoveryProviderProjection
+{
+    @ThriftField(1)
+    public String id;
+
+    public DiscoveryProviderProjection()
+    {
+    }
+
+    public DiscoveryProviderProjection(String id)
+    {
+        this.id = id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryService.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryService.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryService.java
new file mode 100644
index 0000000..edfc141
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryService.java
@@ -0,0 +1,211 @@
+package org.apache.curator.x.rpc.idl.discovery;
+
+import com.facebook.swift.service.ThriftMethod;
+import com.facebook.swift.service.ThriftService;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.apache.curator.x.discovery.DownInstancePolicy;
+import org.apache.curator.x.discovery.ProviderStrategy;
+import org.apache.curator.x.discovery.ServiceDiscovery;
+import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.apache.curator.x.discovery.ServiceProvider;
+import org.apache.curator.x.discovery.strategies.RandomStrategy;
+import org.apache.curator.x.discovery.strategies.RoundRobinStrategy;
+import org.apache.curator.x.discovery.strategies.StickyStrategy;
+import org.apache.curator.x.rpc.connections.Closer;
+import org.apache.curator.x.rpc.connections.ConnectionManager;
+import org.apache.curator.x.rpc.connections.CuratorEntry;
+import org.apache.curator.x.rpc.idl.exceptions.RpcException;
+import org.apache.curator.x.rpc.idl.structs.CuratorProjection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@ThriftService
+public class DiscoveryService
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final ConnectionManager connectionManager;
+
+    public DiscoveryService(ConnectionManager connectionManager)
+    {
+        this.connectionManager = connectionManager;
+    }
+
+    @ThriftMethod
+    public DiscoveryProjection startDiscovery(CuratorProjection projection, final String basePath, DiscoveryInstance yourInstance) throws RpcException
+    {
+        try
+        {
+            CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+            final ServiceDiscovery<byte[]> serviceDiscovery = ServiceDiscoveryBuilder
+                .builder(byte[].class)
+                .basePath(basePath)
+                .client(entry.getClient())
+                .thisInstance(null) // TODO
+                .build();
+            serviceDiscovery.start();
+
+            Closer closer = new Closer()
+            {
+                @Override
+                public void close()
+                {
+                    try
+                    {
+                        serviceDiscovery.close();
+                    }
+                    catch ( IOException e )
+                    {
+                        log.error("Could not close ServiceDiscovery with basePath: " + basePath, e);
+                    }
+                }
+            };
+            String id = entry.addThing(serviceDiscovery, closer);
+
+            return new DiscoveryProjection(id);
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public DiscoveryProviderProjection startProvider(CuratorProjection projection, DiscoveryProjection discoveryProjection, final String serviceName, ProviderStrategyType providerStrategy, int downTimeoutMs, int downErrorThreshold) throws RpcException
+    {
+        ProviderStrategy<byte[]> strategy = null;
+        switch ( providerStrategy )
+        {
+            default:
+            case RANDOM:
+            {
+                strategy = new RandomStrategy<byte[]>();
+                break;
+            }
+
+            case STICKY_RANDOM:
+            {
+                strategy = new StickyStrategy<byte[]>(new RandomStrategy<byte[]>());
+                break;
+            }
+
+            case STICKY_ROUND_ROBIN:
+            {
+                strategy = new StickyStrategy<byte[]>(new RoundRobinStrategy<byte[]>());
+                break;
+            }
+
+            case ROUND_ROBIN:
+            {
+                strategy = new RoundRobinStrategy<byte[]>();
+                break;
+            }
+        }
+
+        CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+        @SuppressWarnings("unchecked")
+        ServiceDiscovery<byte[]> serviceDiscovery = CuratorEntry.mustGetThing(entry, discoveryProjection.id, ServiceDiscovery.class);
+        final ServiceProvider<byte[]> serviceProvider = serviceDiscovery
+            .serviceProviderBuilder()
+            .downInstancePolicy(new DownInstancePolicy(downTimeoutMs, TimeUnit.MILLISECONDS, downErrorThreshold))
+            .providerStrategy(strategy)
+            .serviceName(serviceName)
+            .build();
+        try
+        {
+            serviceProvider.start();
+            Closer closer = new Closer()
+            {
+                @Override
+                public void close()
+                {
+                    try
+                    {
+                        serviceProvider.close();
+                    }
+                    catch ( IOException e )
+                    {
+                        log.error("Could not close ServiceProvider with serviceName: " + serviceName, e);
+                    }
+                }
+            };
+            String id = entry.addThing(serviceProvider, closer);
+            return new DiscoveryProviderProjection(id);
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public DiscoveryInstance getInstance(CuratorProjection projection, DiscoveryProviderProjection providerProjection) throws RpcException
+    {
+        CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+        @SuppressWarnings("unchecked")
+        ServiceProvider<byte[]> serviceProvider = CuratorEntry.mustGetThing(entry, providerProjection.id, ServiceProvider.class);
+        try
+        {
+            return new DiscoveryInstance(serviceProvider.getInstance());
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public List<DiscoveryInstance> getAllInstances(CuratorProjection projection, DiscoveryProviderProjection providerProjection) throws RpcException
+    {
+        CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+        @SuppressWarnings("unchecked")
+        ServiceProvider<byte[]> serviceProvider = CuratorEntry.mustGetThing(entry, providerProjection.id, ServiceProvider.class);
+        try
+        {
+            List<ServiceInstance<byte[]>> allInstances = Lists.newArrayList(serviceProvider.getAllInstances());
+            return Lists.transform
+            (
+                allInstances,
+                new Function<ServiceInstance<byte[]>, DiscoveryInstance>()
+                {
+                    @Override
+                    public DiscoveryInstance apply(ServiceInstance<byte[]> instance)
+                    {
+                        return new DiscoveryInstance(instance);
+                    }
+                }
+            );
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public void noteError(CuratorProjection projection, DiscoveryProviderProjection providerProjection, String instanceId) throws RpcException
+    {
+        CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+        @SuppressWarnings("unchecked")
+        ServiceProvider<byte[]> serviceProvider = CuratorEntry.mustGetThing(entry, providerProjection.id, ServiceProvider.class);
+        try
+        {
+            for ( ServiceInstance<byte[]> instance : serviceProvider.getAllInstances() )
+            {
+                if ( instance.getId().equals(instanceId) )
+                {
+                    serviceProvider.noteError(instance);
+                    break;
+                }
+            }
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryServiceLowLevel.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryServiceLowLevel.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryServiceLowLevel.java
new file mode 100644
index 0000000..b08be1d
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/DiscoveryServiceLowLevel.java
@@ -0,0 +1,85 @@
+package org.apache.curator.x.rpc.idl.discovery;
+
+import com.facebook.swift.service.ThriftMethod;
+import com.facebook.swift.service.ThriftService;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.apache.curator.x.discovery.DownInstancePolicy;
+import org.apache.curator.x.discovery.ProviderStrategy;
+import org.apache.curator.x.discovery.ServiceDiscovery;
+import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.apache.curator.x.discovery.ServiceProvider;
+import org.apache.curator.x.discovery.strategies.RandomStrategy;
+import org.apache.curator.x.discovery.strategies.RoundRobinStrategy;
+import org.apache.curator.x.discovery.strategies.StickyStrategy;
+import org.apache.curator.x.rpc.connections.Closer;
+import org.apache.curator.x.rpc.connections.ConnectionManager;
+import org.apache.curator.x.rpc.connections.CuratorEntry;
+import org.apache.curator.x.rpc.idl.exceptions.RpcException;
+import org.apache.curator.x.rpc.idl.structs.CuratorProjection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@ThriftService
+public class DiscoveryServiceLowLevel
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final ConnectionManager connectionManager;
+
+    public DiscoveryServiceLowLevel(ConnectionManager connectionManager)
+    {
+        this.connectionManager = connectionManager;
+    }
+
+    @ThriftMethod
+    public void registerInstance(CuratorProjection projection, DiscoveryProjection discoveryProjection, DiscoveryInstance instance) throws RpcException
+    {
+        try
+        {
+            CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+            @SuppressWarnings("unchecked")
+            ServiceDiscovery<byte[]> serviceDiscovery = CuratorEntry.mustGetThing(entry, discoveryProjection.id, ServiceDiscovery.class);
+            serviceDiscovery.registerService(null); // TODO
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public void updateInstance(CuratorProjection projection, DiscoveryProjection discoveryProjection, DiscoveryInstance instance) throws RpcException
+    {
+        try
+        {
+            CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+            @SuppressWarnings("unchecked")
+            ServiceDiscovery<byte[]> serviceDiscovery = CuratorEntry.mustGetThing(entry, discoveryProjection.id, ServiceDiscovery.class);
+            serviceDiscovery.updateService(null); // TODO
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
+    public void unregisterInstance(CuratorProjection projection, DiscoveryProjection discoveryProjection, DiscoveryInstance instance) throws RpcException
+    {
+        try
+        {
+            CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+            @SuppressWarnings("unchecked")
+            ServiceDiscovery<byte[]> serviceDiscovery = CuratorEntry.mustGetThing(entry, discoveryProjection.id, ServiceDiscovery.class);
+            serviceDiscovery.unregisterService(null); // TODO
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/ProviderStrategyType.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/ProviderStrategyType.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/ProviderStrategyType.java
new file mode 100644
index 0000000..2caf0b0
--- /dev/null
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/discovery/ProviderStrategyType.java
@@ -0,0 +1,9 @@
+package org.apache.curator.x.rpc.idl.discovery;
+
+public enum ProviderStrategyType
+{
+    RANDOM,
+    STICKY_RANDOM,
+    STICKY_ROUND_ROBIN,
+    ROUND_ROBIN
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
index 07397ea..b7a1145 100644
--- a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
@@ -22,7 +22,6 @@ package org.apache.curator.x.rpc.idl.services;
 import com.facebook.swift.service.ThriftMethod;
 import com.facebook.swift.service.ThriftService;
 import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.api.*;
@@ -429,7 +428,7 @@ public class CuratorProjectionService
         {
             CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
 
-            LeaderLatch leaderLatch = getThing(entry, leaderProjection.id, LeaderLatch.class);
+            LeaderLatch leaderLatch = CuratorEntry.mustGetThing(entry, leaderProjection.id, LeaderLatch.class);
             Collection<Participant> participants = leaderLatch.getParticipants();
             return Lists.transform(Lists.newArrayList(participants), new Function<Participant, RpcParticipant>()
                 {
@@ -453,7 +452,7 @@ public class CuratorProjectionService
         {
             CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
 
-            LeaderLatch leaderLatch = getThing(entry, leaderProjection.id, LeaderLatch.class);
+            LeaderLatch leaderLatch = CuratorEntry.mustGetThing(entry, leaderProjection.id, LeaderLatch.class);
             return leaderLatch.hasLeadership();
         }
         catch ( Exception e )
@@ -514,7 +513,7 @@ public class CuratorProjectionService
         {
             CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
 
-            PathChildrenCache pathChildrenCache = getThing(entry, cacheProjection.id, PathChildrenCache.class);
+            PathChildrenCache pathChildrenCache = CuratorEntry.mustGetThing(entry, cacheProjection.id, PathChildrenCache.class);
             return Lists.transform
             (
                 pathChildrenCache.getCurrentData(),
@@ -541,7 +540,7 @@ public class CuratorProjectionService
         {
             CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
 
-            PathChildrenCache pathChildrenCache = getThing(entry, cacheProjection.id, PathChildrenCache.class);
+            PathChildrenCache pathChildrenCache = CuratorEntry.mustGetThing(entry, cacheProjection.id, PathChildrenCache.class);
             return new RpcChildData(pathChildrenCache.getCurrentData(path));
         }
         catch ( Exception e )
@@ -602,7 +601,7 @@ public class CuratorProjectionService
         {
             CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
 
-            NodeCache nodeCache = getThing(entry, cacheProjection.id, NodeCache.class);
+            NodeCache nodeCache = CuratorEntry.mustGetThing(entry, cacheProjection.id, NodeCache.class);
             return new RpcChildData(nodeCache.getCurrentData());
         }
         catch ( Exception e )
@@ -704,11 +703,4 @@ public class CuratorProjectionService
         }
         throw new Exception("That operation is not available");
     }
-
-    private <T> T getThing(CuratorEntry entry, String id, Class<T> clazz)
-    {
-        T thing = entry.getThing(id, clazz);
-        Preconditions.checkNotNull(thing, "No item of type " + clazz.getSimpleName() + " found with id " + id);
-        return thing;
-    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/structs/CuratorProjection.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/structs/CuratorProjection.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/structs/CuratorProjection.java
index a97ca4b..82ea2a3 100644
--- a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/structs/CuratorProjection.java
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/structs/CuratorProjection.java
@@ -18,7 +18,6 @@
  */
 package org.apache.curator.x.rpc.idl.structs;
 
-import com.facebook.swift.codec.ThriftConstructor;
 import com.facebook.swift.codec.ThriftField;
 import com.facebook.swift.codec.ThriftStruct;
 

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/scripts/generate.sh
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/scripts/generate.sh b/curator-x-rpc/src/main/scripts/generate.sh
index 684d8f5..4c76ffa 100755
--- a/curator-x-rpc/src/main/scripts/generate.sh
+++ b/curator-x-rpc/src/main/scripts/generate.sh
@@ -31,7 +31,7 @@ RPC_PATH="$BASE_DIR/curator-x-rpc/target/classes"
 
 CLASSES=""
 
-for p in services structs exceptions; do
+for p in services structs exceptions discovery; do
     for f in `ls -m1 $RPC_PATH/org/apache/curator/x/rpc/idl/$p/*.class | xargs -n 1 basename | sed s/\.[^\.]*$//`; do
         if [[ $f != *[\$]* ]]; then
             CLASSES="$CLASSES org.apache.curator.x.rpc.idl.$p.$f";
@@ -45,6 +45,7 @@ PATHS="$1:$2"
 PATHS="$PATHS:$BASE_DIR/curator-client/target/classes"
 PATHS="$PATHS:$BASE_DIR/curator-framework/target/classes"
 PATHS="$PATHS:$BASE_DIR/curator-recipes/target/classes"
+PATHS="$PATHS:$BASE_DIR/curator-x-discovery/target/classes"
 PATHS="$PATHS:$RPC_PATH"
 
 java -cp $PATHS com.facebook.swift.generator.swift2thrift.Main \

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/main/thrift/curator.thrift
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/thrift/curator.thrift b/curator-x-rpc/src/main/thrift/curator.thrift
index 4de5cff..1008b32 100644
--- a/curator-x-rpc/src/main/thrift/curator.thrift
+++ b/curator-x-rpc/src/main/thrift/curator.thrift
@@ -43,6 +43,14 @@ enum ZooKeeperExceptionType {
   SYSTEMERROR, RUNTIMEINCONSISTENCY, DATAINCONSISTENCY, CONNECTIONLOSS, MARSHALLINGERROR, UNIMPLEMENTED, OPERATIONTIMEOUT, BADARGUMENTS, APIERROR, NOAUTH, NOCHILDRENFOREPHEMERALS, INVALIDACL, AUTHFAILED, SESSIONEXPIRED, INVALIDCALLBACK, SESSIONMOVED, NOTREADONLY
 }
 
+enum DiscoveryInstanceType {
+  DYNAMIC, STATIC, PERMANENT
+}
+
+enum ProviderStrategyType {
+  RANDOM, STICKY_RANDOM, STICKY_ROUND_ROBIN, ROUND_ROBIN
+}
+
 struct CuratorProjection {
   1: string id;
 }
@@ -143,6 +151,14 @@ struct Version {
   1: i32 version;
 }
 
+struct DiscoveryProjection {
+  1: string id;
+}
+
+struct DiscoveryProviderProjection {
+  1: string id;
+}
+
 struct CreateSpec {
   1: string path;
   2: binary data;
@@ -198,6 +214,18 @@ exception CuratorException {
   4: string message;
 }
 
+struct DiscoveryInstance {
+  1: string name;
+  2: string id;
+  3: string address;
+  4: i32 port;
+  5: i32 sslPort;
+  6: binary payload;
+  7: i64 registrationTimeUTC;
+  8: DiscoveryInstanceType serviceType;
+  9: string uriSpec;
+}
+
 struct CuratorEvent {
   2: CuratorEventType type;
   3: i32 resultCode;
@@ -227,7 +255,7 @@ service CuratorService {
   list<ChildData> getPathChildrenCacheData(1: CuratorProjection projection, 2: PathChildrenCacheProjection cacheProjection) throws (1: CuratorException ex1);
   ChildData getPathChildrenCacheDataForPath(1: CuratorProjection projection, 2: PathChildrenCacheProjection cacheProjection, 3: string path) throws (1: CuratorException ex1);
   bool isLeader(1: CuratorProjection projection, 2: LeaderProjection leaderProjection) throws (1: CuratorException ex1);
-  CuratorProjection newCuratorProjection(1: string connectionName);
+  CuratorProjection newCuratorProjection(1: string connectionName) throws (1: CuratorException ex1);
   oneway void pingCuratorProjection(1: CuratorProjection projection);
   Stat setData(1: CuratorProjection projection, 2: SetDataSpec spec) throws (1: CuratorException ex1);
   LeaderResult startLeaderSelector(1: CuratorProjection projection, 2: string path, 3: string participantId, 4: i32 waitForLeadershipMs) throws (1: CuratorException ex1);
@@ -240,3 +268,17 @@ service CuratorService {
 service EventService {
   CuratorEvent getNextEvent(1: CuratorProjection projection) throws (1: CuratorException ex1);
 }
+
+service DiscoveryService {
+  list<DiscoveryInstance> getAllInstances(1: CuratorProjection projection, 2: DiscoveryProviderProjection providerProjection) throws (1: CuratorException ex1);
+  DiscoveryInstance getInstance(1: CuratorProjection projection, 2: DiscoveryProviderProjection providerProjection) throws (1: CuratorException ex1);
+  void noteError(1: CuratorProjection projection, 2: DiscoveryProviderProjection providerProjection, 3: string instanceId) throws (1: CuratorException ex1);
+  DiscoveryProjection startDiscovery(1: CuratorProjection projection, 2: string basePath, 3: DiscoveryInstance yourInstance) throws (1: CuratorException ex1);
+  DiscoveryProviderProjection startProvider(1: CuratorProjection projection, 2: DiscoveryProjection discoveryProjection, 3: string serviceName, 4: ProviderStrategyType providerStrategy, 5: i32 downTimeoutMs, 6: i32 downErrorThreshold) throws (1: CuratorException ex1);
+}
+
+service DiscoveryServiceLowLevel {
+  void registerInstance(1: CuratorProjection projection, 2: DiscoveryProjection discoveryProjection, 3: DiscoveryInstance instance) throws (1: CuratorException ex1);
+  void unregisterInstance(1: CuratorProjection projection, 2: DiscoveryProjection discoveryProjection, 3: DiscoveryInstance instance) throws (1: CuratorException ex1);
+  void updateInstance(1: CuratorProjection projection, 2: DiscoveryProjection discoveryProjection, 3: DiscoveryInstance instance) throws (1: CuratorException ex1);
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/test/java/org/apache/curator/generated/CuratorService.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/generated/CuratorService.java b/curator-x-rpc/src/test/java/org/apache/curator/generated/CuratorService.java
index e944176..e4281d9 100644
--- a/curator-x-rpc/src/test/java/org/apache/curator/generated/CuratorService.java
+++ b/curator-x-rpc/src/test/java/org/apache/curator/generated/CuratorService.java
@@ -62,7 +62,7 @@ public class CuratorService {
 
     public boolean isLeader(CuratorProjection projection, LeaderProjection leaderProjection) throws CuratorException, org.apache.thrift.TException;
 
-    public CuratorProjection newCuratorProjection(String connectionName) throws org.apache.thrift.TException;
+    public CuratorProjection newCuratorProjection(String connectionName) throws CuratorException, org.apache.thrift.TException;
 
     public void pingCuratorProjection(CuratorProjection projection) throws org.apache.thrift.TException;
 
@@ -481,7 +481,7 @@ public class CuratorService {
       throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "isLeader failed: unknown result");
     }
 
-    public CuratorProjection newCuratorProjection(String connectionName) throws org.apache.thrift.TException
+    public CuratorProjection newCuratorProjection(String connectionName) throws CuratorException, org.apache.thrift.TException
     {
       send_newCuratorProjection(connectionName);
       return recv_newCuratorProjection();
@@ -494,13 +494,16 @@ public class CuratorService {
       sendBase("newCuratorProjection", args);
     }
 
-    public CuratorProjection recv_newCuratorProjection() throws org.apache.thrift.TException
+    public CuratorProjection recv_newCuratorProjection() throws CuratorException, org.apache.thrift.TException
     {
       newCuratorProjection_result result = new newCuratorProjection_result();
       receiveBase(result, "newCuratorProjection");
       if (result.isSetSuccess()) {
         return result.success;
       }
+      if (result.ex1 != null) {
+        throw result.ex1;
+      }
       throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "newCuratorProjection failed: unknown result");
     }
 
@@ -1187,7 +1190,7 @@ public class CuratorService {
         prot.writeMessageEnd();
       }
 
-      public CuratorProjection getResult() throws org.apache.thrift.TException {
+      public CuratorProjection getResult() throws CuratorException, org.apache.thrift.TException {
         if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
           throw new IllegalStateException("Method call not finished!");
         }
@@ -1835,7 +1838,11 @@ public class CuratorService {
 
       public newCuratorProjection_result getResult(I iface, newCuratorProjection_args args) throws org.apache.thrift.TException {
         newCuratorProjection_result result = new newCuratorProjection_result();
-        result.success = iface.newCuratorProjection(args.connectionName);
+        try {
+          result.success = iface.newCuratorProjection(args.connectionName);
+        } catch (CuratorException ex1) {
+          result.ex1 = ex1;
+        }
         return result;
       }
     }
@@ -2780,6 +2787,12 @@ public class CuratorService {
             byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;
             org.apache.thrift.TBase msg;
             newCuratorProjection_result result = new newCuratorProjection_result();
+            if (e instanceof CuratorException) {
+                        result.ex1 = (CuratorException) e;
+                        result.setEx1IsSet(true);
+                        msg = result;
+            }
+             else 
             {
               msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
               msg = (org.apache.thrift.TBase)new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage());
@@ -15170,6 +15183,7 @@ public class CuratorService {
     private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("newCuratorProjection_result");
 
     private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRUCT, (short)0);
+    private static final org.apache.thrift.protocol.TField EX1_FIELD_DESC = new org.apache.thrift.protocol.TField("ex1", org.apache.thrift.protocol.TType.STRUCT, (short)1);
 
     private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
     static {
@@ -15178,10 +15192,12 @@ public class CuratorService {
     }
 
     public CuratorProjection success; // required
+    public CuratorException ex1; // required
 
     /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
     public enum _Fields implements org.apache.thrift.TFieldIdEnum {
-      SUCCESS((short)0, "success");
+      SUCCESS((short)0, "success"),
+      EX1((short)1, "ex1");
 
       private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -15198,6 +15214,8 @@ public class CuratorService {
         switch(fieldId) {
           case 0: // SUCCESS
             return SUCCESS;
+          case 1: // EX1
+            return EX1;
           default:
             return null;
         }
@@ -15243,6 +15261,8 @@ public class CuratorService {
       Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
       tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, CuratorProjection.class)));
+      tmpMap.put(_Fields.EX1, new org.apache.thrift.meta_data.FieldMetaData("ex1", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT)));
       metaDataMap = Collections.unmodifiableMap(tmpMap);
       org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(newCuratorProjection_result.class, metaDataMap);
     }
@@ -15251,10 +15271,12 @@ public class CuratorService {
     }
 
     public newCuratorProjection_result(
-      CuratorProjection success)
+      CuratorProjection success,
+      CuratorException ex1)
     {
       this();
       this.success = success;
+      this.ex1 = ex1;
     }
 
     /**
@@ -15264,6 +15286,9 @@ public class CuratorService {
       if (other.isSetSuccess()) {
         this.success = new CuratorProjection(other.success);
       }
+      if (other.isSetEx1()) {
+        this.ex1 = new CuratorException(other.ex1);
+      }
     }
 
     public newCuratorProjection_result deepCopy() {
@@ -15273,6 +15298,7 @@ public class CuratorService {
     @Override
     public void clear() {
       this.success = null;
+      this.ex1 = null;
     }
 
     public CuratorProjection getSuccess() {
@@ -15299,6 +15325,30 @@ public class CuratorService {
       }
     }
 
+    public CuratorException getEx1() {
+      return this.ex1;
+    }
+
+    public newCuratorProjection_result setEx1(CuratorException ex1) {
+      this.ex1 = ex1;
+      return this;
+    }
+
+    public void unsetEx1() {
+      this.ex1 = null;
+    }
+
+    /** Returns true if field ex1 is set (has been assigned a value) and false otherwise */
+    public boolean isSetEx1() {
+      return this.ex1 != null;
+    }
+
+    public void setEx1IsSet(boolean value) {
+      if (!value) {
+        this.ex1 = null;
+      }
+    }
+
     public void setFieldValue(_Fields field, Object value) {
       switch (field) {
       case SUCCESS:
@@ -15309,6 +15359,14 @@ public class CuratorService {
         }
         break;
 
+      case EX1:
+        if (value == null) {
+          unsetEx1();
+        } else {
+          setEx1((CuratorException)value);
+        }
+        break;
+
       }
     }
 
@@ -15317,6 +15375,9 @@ public class CuratorService {
       case SUCCESS:
         return getSuccess();
 
+      case EX1:
+        return getEx1();
+
       }
       throw new IllegalStateException();
     }
@@ -15330,6 +15391,8 @@ public class CuratorService {
       switch (field) {
       case SUCCESS:
         return isSetSuccess();
+      case EX1:
+        return isSetEx1();
       }
       throw new IllegalStateException();
     }
@@ -15356,6 +15419,15 @@ public class CuratorService {
           return false;
       }
 
+      boolean this_present_ex1 = true && this.isSetEx1();
+      boolean that_present_ex1 = true && that.isSetEx1();
+      if (this_present_ex1 || that_present_ex1) {
+        if (!(this_present_ex1 && that_present_ex1))
+          return false;
+        if (!this.ex1.equals(that.ex1))
+          return false;
+      }
+
       return true;
     }
 
@@ -15382,6 +15454,16 @@ public class CuratorService {
           return lastComparison;
         }
       }
+      lastComparison = Boolean.valueOf(isSetEx1()).compareTo(other.isSetEx1());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetEx1()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.ex1, other.ex1);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
       return 0;
     }
 
@@ -15409,6 +15491,14 @@ public class CuratorService {
         sb.append(this.success);
       }
       first = false;
+      if (!first) sb.append(", ");
+      sb.append("ex1:");
+      if (this.ex1 == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.ex1);
+      }
+      first = false;
       sb.append(")");
       return sb.toString();
     }
@@ -15464,6 +15554,15 @@ public class CuratorService {
                 org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
               }
               break;
+            case 1: // EX1
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+                struct.ex1 = new CuratorException();
+                struct.ex1.read(iprot);
+                struct.setEx1IsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
             default:
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
           }
@@ -15484,6 +15583,11 @@ public class CuratorService {
           struct.success.write(oprot);
           oprot.writeFieldEnd();
         }
+        if (struct.ex1 != null) {
+          oprot.writeFieldBegin(EX1_FIELD_DESC);
+          struct.ex1.write(oprot);
+          oprot.writeFieldEnd();
+        }
         oprot.writeFieldStop();
         oprot.writeStructEnd();
       }
@@ -15505,21 +15609,32 @@ public class CuratorService {
         if (struct.isSetSuccess()) {
           optionals.set(0);
         }
-        oprot.writeBitSet(optionals, 1);
+        if (struct.isSetEx1()) {
+          optionals.set(1);
+        }
+        oprot.writeBitSet(optionals, 2);
         if (struct.isSetSuccess()) {
           struct.success.write(oprot);
         }
+        if (struct.isSetEx1()) {
+          struct.ex1.write(oprot);
+        }
       }
 
       @Override
       public void read(org.apache.thrift.protocol.TProtocol prot, newCuratorProjection_result struct) throws org.apache.thrift.TException {
         TTupleProtocol iprot = (TTupleProtocol) prot;
-        BitSet incoming = iprot.readBitSet(1);
+        BitSet incoming = iprot.readBitSet(2);
         if (incoming.get(0)) {
           struct.success = new CuratorProjection();
           struct.success.read(iprot);
           struct.setSuccessIsSet(true);
         }
+        if (incoming.get(1)) {
+          struct.ex1 = new CuratorException();
+          struct.ex1.read(iprot);
+          struct.setEx1IsSet(true);
+        }
       }
     }
 

http://git-wip-us.apache.org/repos/asf/curator/blob/87582a9b/curator-x-rpc/src/test/java/org/apache/curator/generated/DiscoveryInstance.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/generated/DiscoveryInstance.java b/curator-x-rpc/src/test/java/org/apache/curator/generated/DiscoveryInstance.java
new file mode 100644
index 0000000..b73be31
--- /dev/null
+++ b/curator-x-rpc/src/test/java/org/apache/curator/generated/DiscoveryInstance.java
@@ -0,0 +1,1201 @@
+/**
+ * Autogenerated by Thrift Compiler (0.9.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.curator.generated;
+
+import org.apache.thrift.scheme.IScheme;
+import org.apache.thrift.scheme.SchemeFactory;
+import org.apache.thrift.scheme.StandardScheme;
+
+import org.apache.thrift.scheme.TupleScheme;
+import org.apache.thrift.protocol.TTupleProtocol;
+import org.apache.thrift.protocol.TProtocolException;
+import org.apache.thrift.EncodingUtils;
+import org.apache.thrift.TException;
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.apache.thrift.server.AbstractNonblockingServer.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.EnumMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.EnumSet;
+import java.util.Collections;
+import java.util.BitSet;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DiscoveryInstance implements org.apache.thrift.TBase<DiscoveryInstance, DiscoveryInstance._Fields>, java.io.Serializable, Cloneable, Comparable<DiscoveryInstance> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("DiscoveryInstance");
+
+  private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1);
+  private static final org.apache.thrift.protocol.TField ID_FIELD_DESC = new org.apache.thrift.protocol.TField("id", org.apache.thrift.protocol.TType.STRING, (short)2);
+  private static final org.apache.thrift.protocol.TField ADDRESS_FIELD_DESC = new org.apache.thrift.protocol.TField("address", org.apache.thrift.protocol.TType.STRING, (short)3);
+  private static final org.apache.thrift.protocol.TField PORT_FIELD_DESC = new org.apache.thrift.protocol.TField("port", org.apache.thrift.protocol.TType.I32, (short)4);
+  private static final org.apache.thrift.protocol.TField SSL_PORT_FIELD_DESC = new org.apache.thrift.protocol.TField("sslPort", org.apache.thrift.protocol.TType.I32, (short)5);
+  private static final org.apache.thrift.protocol.TField PAYLOAD_FIELD_DESC = new org.apache.thrift.protocol.TField("payload", org.apache.thrift.protocol.TType.STRING, (short)6);
+  private static final org.apache.thrift.protocol.TField REGISTRATION_TIME_UTC_FIELD_DESC = new org.apache.thrift.protocol.TField("registrationTimeUTC", org.apache.thrift.protocol.TType.I64, (short)7);
+  private static final org.apache.thrift.protocol.TField SERVICE_TYPE_FIELD_DESC = new org.apache.thrift.protocol.TField("serviceType", org.apache.thrift.protocol.TType.I32, (short)8);
+  private static final org.apache.thrift.protocol.TField URI_SPEC_FIELD_DESC = new org.apache.thrift.protocol.TField("uriSpec", org.apache.thrift.protocol.TType.STRING, (short)9);
+
+  private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
+  static {
+    schemes.put(StandardScheme.class, new DiscoveryInstanceStandardSchemeFactory());
+    schemes.put(TupleScheme.class, new DiscoveryInstanceTupleSchemeFactory());
+  }
+
+  public String name; // required
+  public String id; // required
+  public String address; // required
+  public int port; // required
+  public int sslPort; // required
+  public ByteBuffer payload; // required
+  public long registrationTimeUTC; // required
+  /**
+   * 
+   * @see DiscoveryInstanceType
+   */
+  public DiscoveryInstanceType serviceType; // required
+  public String uriSpec; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    NAME((short)1, "name"),
+    ID((short)2, "id"),
+    ADDRESS((short)3, "address"),
+    PORT((short)4, "port"),
+    SSL_PORT((short)5, "sslPort"),
+    PAYLOAD((short)6, "payload"),
+    REGISTRATION_TIME_UTC((short)7, "registrationTimeUTC"),
+    /**
+     * 
+     * @see DiscoveryInstanceType
+     */
+    SERVICE_TYPE((short)8, "serviceType"),
+    URI_SPEC((short)9, "uriSpec");
+
+    private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
+
+    static {
+      for (_Fields field : EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // NAME
+          return NAME;
+        case 2: // ID
+          return ID;
+        case 3: // ADDRESS
+          return ADDRESS;
+        case 4: // PORT
+          return PORT;
+        case 5: // SSL_PORT
+          return SSL_PORT;
+        case 6: // PAYLOAD
+          return PAYLOAD;
+        case 7: // REGISTRATION_TIME_UTC
+          return REGISTRATION_TIME_UTC;
+        case 8: // SERVICE_TYPE
+          return SERVICE_TYPE;
+        case 9: // URI_SPEC
+          return URI_SPEC;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    public static _Fields findByName(String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final String _fieldName;
+
+    _Fields(short thriftId, String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  private static final int __PORT_ISSET_ID = 0;
+  private static final int __SSLPORT_ISSET_ID = 1;
+  private static final int __REGISTRATIONTIMEUTC_ISSET_ID = 2;
+  private byte __isset_bitfield = 0;
+  public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.ID, new org.apache.thrift.meta_data.FieldMetaData("id", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.ADDRESS, new org.apache.thrift.meta_data.FieldMetaData("address", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.PORT, new org.apache.thrift.meta_data.FieldMetaData("port", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.SSL_PORT, new org.apache.thrift.meta_data.FieldMetaData("sslPort", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.PAYLOAD, new org.apache.thrift.meta_data.FieldMetaData("payload", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , true)));
+    tmpMap.put(_Fields.REGISTRATION_TIME_UTC, new org.apache.thrift.meta_data.FieldMetaData("registrationTimeUTC", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
+    tmpMap.put(_Fields.SERVICE_TYPE, new org.apache.thrift.meta_data.FieldMetaData("serviceType", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, DiscoveryInstanceType.class)));
+    tmpMap.put(_Fields.URI_SPEC, new org.apache.thrift.meta_data.FieldMetaData("uriSpec", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(DiscoveryInstance.class, metaDataMap);
+  }
+
+  public DiscoveryInstance() {
+  }
+
+  public DiscoveryInstance(
+    String name,
+    String id,
+    String address,
+    int port,
+    int sslPort,
+    ByteBuffer payload,
+    long registrationTimeUTC,
+    DiscoveryInstanceType serviceType,
+    String uriSpec)
+  {
+    this();
+    this.name = name;
+    this.id = id;
+    this.address = address;
+    this.port = port;
+    setPortIsSet(true);
+    this.sslPort = sslPort;
+    setSslPortIsSet(true);
+    this.payload = payload;
+    this.registrationTimeUTC = registrationTimeUTC;
+    setRegistrationTimeUTCIsSet(true);
+    this.serviceType = serviceType;
+    this.uriSpec = uriSpec;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public DiscoveryInstance(DiscoveryInstance other) {
+    __isset_bitfield = other.__isset_bitfield;
+    if (other.isSetName()) {
+      this.name = other.name;
+    }
+    if (other.isSetId()) {
+      this.id = other.id;
+    }
+    if (other.isSetAddress()) {
+      this.address = other.address;
+    }
+    this.port = other.port;
+    this.sslPort = other.sslPort;
+    if (other.isSetPayload()) {
+      this.payload = org.apache.thrift.TBaseHelper.copyBinary(other.payload);
+;
+    }
+    this.registrationTimeUTC = other.registrationTimeUTC;
+    if (other.isSetServiceType()) {
+      this.serviceType = other.serviceType;
+    }
+    if (other.isSetUriSpec()) {
+      this.uriSpec = other.uriSpec;
+    }
+  }
+
+  public DiscoveryInstance deepCopy() {
+    return new DiscoveryInstance(this);
+  }
+
+  @Override
+  public void clear() {
+    this.name = null;
+    this.id = null;
+    this.address = null;
+    setPortIsSet(false);
+    this.port = 0;
+    setSslPortIsSet(false);
+    this.sslPort = 0;
+    this.payload = null;
+    setRegistrationTimeUTCIsSet(false);
+    this.registrationTimeUTC = 0;
+    this.serviceType = null;
+    this.uriSpec = null;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public DiscoveryInstance setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public void unsetName() {
+    this.name = null;
+  }
+
+  /** Returns true if field name is set (has been assigned a value) and false otherwise */
+  public boolean isSetName() {
+    return this.name != null;
+  }
+
+  public void setNameIsSet(boolean value) {
+    if (!value) {
+      this.name = null;
+    }
+  }
+
+  public String getId() {
+    return this.id;
+  }
+
+  public DiscoveryInstance setId(String id) {
+    this.id = id;
+    return this;
+  }
+
+  public void unsetId() {
+    this.id = null;
+  }
+
+  /** Returns true if field id is set (has been assigned a value) and false otherwise */
+  public boolean isSetId() {
+    return this.id != null;
+  }
+
+  public void setIdIsSet(boolean value) {
+    if (!value) {
+      this.id = null;
+    }
+  }
+
+  public String getAddress() {
+    return this.address;
+  }
+
+  public DiscoveryInstance setAddress(String address) {
+    this.address = address;
+    return this;
+  }
+
+  public void unsetAddress() {
+    this.address = null;
+  }
+
+  /** Returns true if field address is set (has been assigned a value) and false otherwise */
+  public boolean isSetAddress() {
+    return this.address != null;
+  }
+
+  public void setAddressIsSet(boolean value) {
+    if (!value) {
+      this.address = null;
+    }
+  }
+
+  public int getPort() {
+    return this.port;
+  }
+
+  public DiscoveryInstance setPort(int port) {
+    this.port = port;
+    setPortIsSet(true);
+    return this;
+  }
+
+  public void unsetPort() {
+    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __PORT_ISSET_ID);
+  }
+
+  /** Returns true if field port is set (has been assigned a value) and false otherwise */
+  public boolean isSetPort() {
+    return EncodingUtils.testBit(__isset_bitfield, __PORT_ISSET_ID);
+  }
+
+  public void setPortIsSet(boolean value) {
+    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __PORT_ISSET_ID, value);
+  }
+
+  public int getSslPort() {
+    return this.sslPort;
+  }
+
+  public DiscoveryInstance setSslPort(int sslPort) {
+    this.sslPort = sslPort;
+    setSslPortIsSet(true);
+    return this;
+  }
+
+  public void unsetSslPort() {
+    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __SSLPORT_ISSET_ID);
+  }
+
+  /** Returns true if field sslPort is set (has been assigned a value) and false otherwise */
+  public boolean isSetSslPort() {
+    return EncodingUtils.testBit(__isset_bitfield, __SSLPORT_ISSET_ID);
+  }
+
+  public void setSslPortIsSet(boolean value) {
+    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __SSLPORT_ISSET_ID, value);
+  }
+
+  public byte[] getPayload() {
+    setPayload(org.apache.thrift.TBaseHelper.rightSize(payload));
+    return payload == null ? null : payload.array();
+  }
+
+  public ByteBuffer bufferForPayload() {
+    return payload;
+  }
+
+  public DiscoveryInstance setPayload(byte[] payload) {
+    setPayload(payload == null ? (ByteBuffer)null : ByteBuffer.wrap(payload));
+    return this;
+  }
+
+  public DiscoveryInstance setPayload(ByteBuffer payload) {
+    this.payload = payload;
+    return this;
+  }
+
+  public void unsetPayload() {
+    this.payload = null;
+  }
+
+  /** Returns true if field payload is set (has been assigned a value) and false otherwise */
+  public boolean isSetPayload() {
+    return this.payload != null;
+  }
+
+  public void setPayloadIsSet(boolean value) {
+    if (!value) {
+      this.payload = null;
+    }
+  }
+
+  public long getRegistrationTimeUTC() {
+    return this.registrationTimeUTC;
+  }
+
+  public DiscoveryInstance setRegistrationTimeUTC(long registrationTimeUTC) {
+    this.registrationTimeUTC = registrationTimeUTC;
+    setRegistrationTimeUTCIsSet(true);
+    return this;
+  }
+
+  public void unsetRegistrationTimeUTC() {
+    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __REGISTRATIONTIMEUTC_ISSET_ID);
+  }
+
+  /** Returns true if field registrationTimeUTC is set (has been assigned a value) and false otherwise */
+  public boolean isSetRegistrationTimeUTC() {
+    return EncodingUtils.testBit(__isset_bitfield, __REGISTRATIONTIMEUTC_ISSET_ID);
+  }
+
+  public void setRegistrationTimeUTCIsSet(boolean value) {
+    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __REGISTRATIONTIMEUTC_ISSET_ID, value);
+  }
+
+  /**
+   * 
+   * @see DiscoveryInstanceType
+   */
+  public DiscoveryInstanceType getServiceType() {
+    return this.serviceType;
+  }
+
+  /**
+   * 
+   * @see DiscoveryInstanceType
+   */
+  public DiscoveryInstance setServiceType(DiscoveryInstanceType serviceType) {
+    this.serviceType = serviceType;
+    return this;
+  }
+
+  public void unsetServiceType() {
+    this.serviceType = null;
+  }
+
+  /** Returns true if field serviceType is set (has been assigned a value) and false otherwise */
+  public boolean isSetServiceType() {
+    return this.serviceType != null;
+  }
+
+  public void setServiceTypeIsSet(boolean value) {
+    if (!value) {
+      this.serviceType = null;
+    }
+  }
+
+  public String getUriSpec() {
+    return this.uriSpec;
+  }
+
+  public DiscoveryInstance setUriSpec(String uriSpec) {
+    this.uriSpec = uriSpec;
+    return this;
+  }
+
+  public void unsetUriSpec() {
+    this.uriSpec = null;
+  }
+
+  /** Returns true if field uriSpec is set (has been assigned a value) and false otherwise */
+  public boolean isSetUriSpec() {
+    return this.uriSpec != null;
+  }
+
+  public void setUriSpecIsSet(boolean value) {
+    if (!value) {
+      this.uriSpec = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, Object value) {
+    switch (field) {
+    case NAME:
+      if (value == null) {
+        unsetName();
+      } else {
+        setName((String)value);
+      }
+      break;
+
+    case ID:
+      if (value == null) {
+        unsetId();
+      } else {
+        setId((String)value);
+      }
+      break;
+
+    case ADDRESS:
+      if (value == null) {
+        unsetAddress();
+      } else {
+        setAddress((String)value);
+      }
+      break;
+
+    case PORT:
+      if (value == null) {
+        unsetPort();
+      } else {
+        setPort((Integer)value);
+      }
+      break;
+
+    case SSL_PORT:
+      if (value == null) {
+        unsetSslPort();
+      } else {
+        setSslPort((Integer)value);
+      }
+      break;
+
+    case PAYLOAD:
+      if (value == null) {
+        unsetPayload();
+      } else {
+        setPayload((ByteBuffer)value);
+      }
+      break;
+
+    case REGISTRATION_TIME_UTC:
+      if (value == null) {
+        unsetRegistrationTimeUTC();
+      } else {
+        setRegistrationTimeUTC((Long)value);
+      }
+      break;
+
+    case SERVICE_TYPE:
+      if (value == null) {
+        unsetServiceType();
+      } else {
+        setServiceType((DiscoveryInstanceType)value);
+      }
+      break;
+
+    case URI_SPEC:
+      if (value == null) {
+        unsetUriSpec();
+      } else {
+        setUriSpec((String)value);
+      }
+      break;
+
+    }
+  }
+
+  public Object getFieldValue(_Fields field) {
+    switch (field) {
+    case NAME:
+      return getName();
+
+    case ID:
+      return getId();
+
+    case ADDRESS:
+      return getAddress();
+
+    case PORT:
+      return Integer.valueOf(getPort());
+
+    case SSL_PORT:
+      return Integer.valueOf(getSslPort());
+
+    case PAYLOAD:
+      return getPayload();
+
+    case REGISTRATION_TIME_UTC:
+      return Long.valueOf(getRegistrationTimeUTC());
+
+    case SERVICE_TYPE:
+      return getServiceType();
+
+    case URI_SPEC:
+      return getUriSpec();
+
+    }
+    throw new IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new IllegalArgumentException();
+    }
+
+    switch (field) {
+    case NAME:
+      return isSetName();
+    case ID:
+      return isSetId();
+    case ADDRESS:
+      return isSetAddress();
+    case PORT:
+      return isSetPort();
+    case SSL_PORT:
+      return isSetSslPort();
+    case PAYLOAD:
+      return isSetPayload();
+    case REGISTRATION_TIME_UTC:
+      return isSetRegistrationTimeUTC();
+    case SERVICE_TYPE:
+      return isSetServiceType();
+    case URI_SPEC:
+      return isSetUriSpec();
+    }
+    throw new IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if (that == null)
+      return false;
+    if (that instanceof DiscoveryInstance)
+      return this.equals((DiscoveryInstance)that);
+    return false;
+  }
+
+  public boolean equals(DiscoveryInstance that) {
+    if (that == null)
+      return false;
+
+    boolean this_present_name = true && this.isSetName();
+    boolean that_present_name = true && that.isSetName();
+    if (this_present_name || that_present_name) {
+      if (!(this_present_name && that_present_name))
+        return false;
+      if (!this.name.equals(that.name))
+        return false;
+    }
+
+    boolean this_present_id = true && this.isSetId();
+    boolean that_present_id = true && that.isSetId();
+    if (this_present_id || that_present_id) {
+      if (!(this_present_id && that_present_id))
+        return false;
+      if (!this.id.equals(that.id))
+        return false;
+    }
+
+    boolean this_present_address = true && this.isSetAddress();
+    boolean that_present_address = true && that.isSetAddress();
+    if (this_present_address || that_present_address) {
+      if (!(this_present_address && that_present_address))
+        return false;
+      if (!this.address.equals(that.address))
+        return false;
+    }
+
+    boolean this_present_port = true;
+    boolean that_present_port = true;
+    if (this_present_port || that_present_port) {
+      if (!(this_present_port && that_present_port))
+        return false;
+      if (this.port != that.port)
+        return false;
+    }
+
+    boolean this_present_sslPort = true;
+    boolean that_present_sslPort = true;
+    if (this_present_sslPort || that_present_sslPort) {
+      if (!(this_present_sslPort && that_present_sslPort))
+        return false;
+      if (this.sslPort != that.sslPort)
+        return false;
+    }
+
+    boolean this_present_payload = true && this.isSetPayload();
+    boolean that_present_payload = true && that.isSetPayload();
+    if (this_present_payload || that_present_payload) {
+      if (!(this_present_payload && that_present_payload))
+        return false;
+      if (!this.payload.equals(that.payload))
+        return false;
+    }
+
+    boolean this_present_registrationTimeUTC = true;
+    boolean that_present_registrationTimeUTC = true;
+    if (this_present_registrationTimeUTC || that_present_registrationTimeUTC) {
+      if (!(this_present_registrationTimeUTC && that_present_registrationTimeUTC))
+        return false;
+      if (this.registrationTimeUTC != that.registrationTimeUTC)
+        return false;
+    }
+
+    boolean this_present_serviceType = true && this.isSetServiceType();
+    boolean that_present_serviceType = true && that.isSetServiceType();
+    if (this_present_serviceType || that_present_serviceType) {
+      if (!(this_present_serviceType && that_present_serviceType))
+        return false;
+      if (!this.serviceType.equals(that.serviceType))
+        return false;
+    }
+
+    boolean this_present_uriSpec = true && this.isSetUriSpec();
+    boolean that_present_uriSpec = true && that.isSetUriSpec();
+    if (this_present_uriSpec || that_present_uriSpec) {
+      if (!(this_present_uriSpec && that_present_uriSpec))
+        return false;
+      if (!this.uriSpec.equals(that.uriSpec))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return 0;
+  }
+
+  @Override
+  public int compareTo(DiscoveryInstance other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = Boolean.valueOf(isSetName()).compareTo(other.isSetName());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetName()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, other.name);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetId()).compareTo(other.isSetId());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetId()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.id, other.id);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetAddress()).compareTo(other.isSetAddress());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetAddress()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.address, other.address);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetPort()).compareTo(other.isSetPort());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetPort()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.port, other.port);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetSslPort()).compareTo(other.isSetSslPort());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetSslPort()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.sslPort, other.sslPort);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetPayload()).compareTo(other.isSetPayload());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetPayload()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.payload, other.payload);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetRegistrationTimeUTC()).compareTo(other.isSetRegistrationTimeUTC());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetRegistrationTimeUTC()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.registrationTimeUTC, other.registrationTimeUTC);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetServiceType()).compareTo(other.isSetServiceType());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetServiceType()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.serviceType, other.serviceType);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = Boolean.valueOf(isSetUriSpec()).compareTo(other.isSetUriSpec());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetUriSpec()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.uriSpec, other.uriSpec);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder("DiscoveryInstance(");
+    boolean first = true;
+
+    sb.append("name:");
+    if (this.name == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.name);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("id:");
+    if (this.id == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.id);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("address:");
+    if (this.address == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.address);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("port:");
+    sb.append(this.port);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("sslPort:");
+    sb.append(this.sslPort);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("payload:");
+    if (this.payload == null) {
+      sb.append("null");
+    } else {
+      org.apache.thrift.TBaseHelper.toString(this.payload, sb);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("registrationTimeUTC:");
+    sb.append(this.registrationTimeUTC);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("serviceType:");
+    if (this.serviceType == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.serviceType);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("uriSpec:");
+    if (this.uriSpec == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.uriSpec);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
+    try {
+      // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
+      __isset_bitfield = 0;
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class DiscoveryInstanceStandardSchemeFactory implements SchemeFactory {
+    public DiscoveryInstanceStandardScheme getScheme() {
+      return new DiscoveryInstanceStandardScheme();
+    }
+  }
+
+  private static class DiscoveryInstanceStandardScheme extends StandardScheme<DiscoveryInstance> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, DiscoveryInstance struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // NAME
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.name = iprot.readString();
+              struct.setNameIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // ID
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.id = iprot.readString();
+              struct.setIdIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 3: // ADDRESS
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.address = iprot.readString();
+              struct.setAddressIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 4: // PORT
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.port = iprot.readI32();
+              struct.setPortIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 5: // SSL_PORT
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.sslPort = iprot.readI32();
+              struct.setSslPortIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 6: // PAYLOAD
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.payload = iprot.readBinary();
+              struct.setPayloadIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 7: // REGISTRATION_TIME_UTC
+            if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+              struct.registrationTimeUTC = iprot.readI64();
+              struct.setRegistrationTimeUTCIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 8: // SERVICE_TYPE
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.serviceType = DiscoveryInstanceType.findByValue(iprot.readI32());
+              struct.setServiceTypeIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 9: // URI_SPEC
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.uriSpec = iprot.readString();
+              struct.setUriSpecIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, DiscoveryInstance struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.name != null) {
+        oprot.writeFieldBegin(NAME_FIELD_DESC);
+        oprot.writeString(struct.name);
+        oprot.writeFieldEnd();
+      }
+      if (struct.id != null) {
+        oprot.writeFieldBegin(ID_FIELD_DESC);
+        oprot.writeString(struct.id);
+        oprot.writeFieldEnd();
+      }
+      if (struct.address != null) {
+        oprot.writeFieldBegin(ADDRESS_FIELD_DESC);
+        oprot.writeString(struct.address);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldBegin(PORT_FIELD_DESC);
+      oprot.writeI32(struct.port);
+      oprot.writeFieldEnd();
+      oprot.writeFieldBegin(SSL_PORT_FIELD_DESC);
+      oprot.writeI32(struct.sslPort);
+      oprot.writeFieldEnd();
+      if (struct.payload != null) {
+        oprot.writeFieldBegin(PAYLOAD_FIELD_DESC);
+        oprot.writeBinary(struct.payload);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldBegin(REGISTRATION_TIME_UTC_FIELD_DESC);
+      oprot.writeI64(struct.registrationTimeUTC);
+      oprot.writeFieldEnd();
+      if (struct.serviceType != null) {
+        oprot.writeFieldBegin(SERVICE_TYPE_FIELD_DESC);
+        oprot.writeI32(struct.serviceType.getValue());
+        oprot.writeFieldEnd();
+      }
+      if (struct.uriSpec != null) {
+        oprot.writeFieldBegin(URI_SPEC_FIELD_DESC);
+        oprot.writeString(struct.uriSpec);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class DiscoveryInstanceTupleSchemeFactory implements SchemeFactory {
+    public DiscoveryInstanceTupleScheme getScheme() {
+      return new DiscoveryInstanceTupleScheme();
+    }
+  }
+
+  private static class DiscoveryInstanceTupleScheme extends TupleScheme<DiscoveryInstance> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, DiscoveryInstance struct) throws org.apache.thrift.TException {
+      TTupleProtocol oprot = (TTupleProtocol) prot;
+      BitSet optionals = new BitSet();
+      if (struct.isSetName()) {
+        optionals.set(0);
+      }
+      if (struct.isSetId()) {
+        optionals.set(1);
+      }
+      if (struct.isSetAddress()) {
+        optionals.set(2);
+      }
+      if (struct.isSetPort()) {
+        optionals.set(3);
+      }
+      if (struct.isSetSslPort()) {
+        optionals.set(4);
+      }
+      if (struct.isSetPayload()) {
+        optionals.set(5);
+      }
+      if (struct.isSetRegistrationTimeUTC()) {
+        optionals.set(6);
+      }
+      if (struct.isSetServiceType()) {
+        optionals.set(7);
+      }
+      if (struct.isSetUriSpec()) {
+        optionals.set(8);
+      }
+      oprot.writeBitSet(optionals, 9);
+      if (struct.isSetName()) {
+        oprot.writeString(struct.name);
+      }
+      if (struct.isSetId()) {
+        oprot.writeString(struct.id);
+      }
+      if (struct.isSetAddress()) {
+        oprot.writeString(struct.address);
+      }
+      if (struct.isSetPort()) {
+        oprot.writeI32(struct.port);
+      }
+      if (struct.isSetSslPort()) {
+        oprot.writeI32(struct.sslPort);
+      }
+      if (struct.isSetPayload()) {
+        oprot.writeBinary(struct.payload);
+      }
+      if (struct.isSetRegistrationTimeUTC()) {
+        oprot.writeI64(struct.registrationTimeUTC);
+      }
+      if (struct.isSetServiceType()) {
+        oprot.writeI32(struct.serviceType.getValue());
+      }
+      if (struct.isSetUriSpec()) {
+        oprot.writeString(struct.uriSpec);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, DiscoveryInstance struct) throws org.apache.thrift.TException {
+      TTupleProtocol iprot = (TTupleProtocol) prot;
+      BitSet incoming = iprot.readBitSet(9);
+      if (incoming.get(0)) {
+        struct.name = iprot.readString();
+        struct.setNameIsSet(true);
+      }
+      if (incoming.get(1)) {
+        struct.id = iprot.readString();
+        struct.setIdIsSet(true);
+      }
+      if (incoming.get(2)) {
+        struct.address = iprot.readString();
+        struct.setAddressIsSet(true);
+      }
+      if (incoming.get(3)) {
+        struct.port = iprot.readI32();
+        struct.setPortIsSet(true);
+      }
+      if (incoming.get(4)) {
+        struct.sslPort = iprot.readI32();
+        struct.setSslPortIsSet(true);
+      }
+      if (incoming.get(5)) {
+        struct.payload = iprot.readBinary();
+        struct.setPayloadIsSet(true);
+      }
+      if (incoming.get(6)) {
+        struct.registrationTimeUTC = iprot.readI64();
+        struct.setRegistrationTimeUTCIsSet(true);
+      }
+      if (incoming.get(7)) {
+        struct.serviceType = DiscoveryInstanceType.findByValue(iprot.readI32());
+        struct.setServiceTypeIsSet(true);
+      }
+      if (incoming.get(8)) {
+        struct.uriSpec = iprot.readString();
+        struct.setUriSpecIsSet(true);
+      }
+    }
+  }
+
+}
+