diff --git a/examples/pom.xml b/examples/pom.xml
index 03bdf908de..24df486232 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -24,6 +24,11 @@
client-java-util
0.2-SNAPSHOT
+
+ io.kubernetes
+ client-java-proto
+ 0.2-SNAPSHOT
+
com.google.guava
guava
diff --git a/examples/src/main/java/io/kubernetes/client/examples/ProtoExample.java b/examples/src/main/java/io/kubernetes/client/examples/ProtoExample.java
new file mode 100644
index 0000000000..b78dd5d14b
--- /dev/null
+++ b/examples/src/main/java/io/kubernetes/client/examples/ProtoExample.java
@@ -0,0 +1,47 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+Licensed 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 io.kubernetes.client.examples;
+
+import io.kubernetes.client.ApiClient;
+import io.kubernetes.client.ApiException;
+import io.kubernetes.client.Configuration;
+import io.kubernetes.client.ProtoClient;
+import io.kubernetes.client.proto.V1.Pod;
+import io.kubernetes.client.proto.V1.PodList;
+import io.kubernetes.client.util.Config;
+
+import java.io.IOException;
+
+
+/**
+ * A simple example of how to use the Java API
+ *
+ * Easiest way to run this:
+ * mvn exec:java -Dexec.mainClass="io.kubernetes.client.examples.ProtoExample"
+ *
+ * From inside $REPO_DIR/examples
+ */
+public class ProtoExample {
+ public static void main(String[] args) throws IOException, ApiException, InterruptedException {
+ ApiClient client = Config.defaultClient();
+ Configuration.setDefaultApiClient(client);
+
+ ProtoClient pc = new ProtoClient(client);
+ PodList list = pc.list(PodList.newBuilder(), "/api/v1/namespaces/default/pods");
+
+ if (list.getItemsCount() > 0) {
+ Pod p = list.getItems(0);
+ System.out.println(p.toString());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 6e15168886..4ee7122476 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
util
examples
kubernetes
+ proto
diff --git a/proto/pom.xml b/proto/pom.xml
index 812f546e40..7a53978423 100644
--- a/proto/pom.xml
+++ b/proto/pom.xml
@@ -2,7 +2,7 @@
4.0.0
io.kubernetes
client-java-proto
- 0.1-SNAPSHOT
+ 0.2-SNAPSHOT
jar
client-java-proto
https://github.com/kubernetes-client/java
diff --git a/util/pom.xml b/util/pom.xml
index 837eaf324b..92f968360c 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -17,6 +17,11 @@
client-java-api
0.2-SNAPSHOT
+
+ io.kubernetes
+ client-java-proto
+ 0.2-SNAPSHOT
+
org.yaml
snakeyaml
@@ -59,6 +64,11 @@
system-rules
1.16.1
+
+ com.google.protobuf
+ protobuf-java
+ 3.4.0
+
diff --git a/util/src/main/java/io/kubernetes/client/ProtoClient.java b/util/src/main/java/io/kubernetes/client/ProtoClient.java
new file mode 100644
index 0000000000..5aefc0b17e
--- /dev/null
+++ b/util/src/main/java/io/kubernetes/client/ProtoClient.java
@@ -0,0 +1,112 @@
+package io.kubernetes.client;
+
+import io.kubernetes.client.ApiException;
+import io.kubernetes.client.Configuration;
+import io.kubernetes.client.proto.Runtime.Unknown;
+
+import com.google.common.io.ByteStreams;
+import com.google.protobuf.Message;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
+import com.squareup.okhttp.ResponseBody;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class ProtoClient {
+ private ApiClient apiClient;
+ // Magic number for the beginning of proto encoded.
+ // https://github.com/kubernetes/apimachinery/blob/master/pkg/runtime/serializer/protobuf/protobuf.go#L42
+ private static final byte[] MAGIC = new byte[] { 0x6b, 0x38, 0x73, 0x00 };
+
+ /**
+ * Simple Protocol Budder API client constructor, uses default configuration
+ */
+ public ProtoClient() {
+ this(Configuration.getDefaultApiClient());
+ }
+
+ /**
+ * ProtocolBuffer Client Constructor
+ * @param apiClient The api client to use.
+ */
+ public ProtoClient(ApiClient apiClient) {
+ this.apiClient = apiClient;
+ }
+
+ /**
+ * Get the API client for these ProtocolBuffer operations.
+ * @return The API client that will be used.
+ */
+ public ApiClient getApiClient() {
+ return apiClient;
+ }
+
+ /**
+ * Set the API client for subsequent ProtocolBuffer operations.
+ * @param apiClient The new API client to use.
+ */
+ public void setApiClient(ApiClient apiClient) {
+ this.apiClient = apiClient;
+ }
+
+ /**
+ * Get a Kubernetes API object using protocol buffer encoding.
+ * @param builder The appropriate Builder for the object receveived from the request.
+ * @param path The URL path to call (e.g. /api/v1/namespaces/default/pods/pod-name)
+ * @return A Message of type T
+ */
+ public T get(T.Builder builder, String path) throws ApiException, IOException {
+ return (T) request(builder, path, "GET");
+ }
+
+ /**
+ * List is fluent, semantic sugar method on top of get, which is intended
+ * to convey that the object is a List of objects rather than a single object
+ * @param builder The appropriate Builder for the object receveived from the request.
+ * @param path The URL path to call (e.g. /api/v1/namespaces/default/pods/pod-name)
+ * @return A Message of type T
+ */
+ public T list(T.Builder listObj, String path) throws ApiException, IOException {
+ return get(listObj, path);
+ }
+
+ /**
+ * Generic protocol buffer based HTTP request.
+ * Not intended for general consumption, but public for advance use cases.
+ * @param builder The appropriate Builder for the object receveived from the request.
+ * @param method The HTTP method (e.g. GET) for this request.
+ * @param path The URL path to call (e.g. /api/v1/namespaces/default/pods/pod-name)
+ * @return A Message of type T
+ */
+ public T request(T.Builder builder, String path, String method) throws ApiException, IOException {
+ HashMap headers = new HashMap();
+ headers.put("Content-type", "application/vnd.kubernetes.protobuf");
+ headers.put("Accept", "application/vnd.kubernetes.protobuf");
+ Request request = apiClient.buildRequest(path, method, new ArrayList(), new ArrayList(), null,
+ headers, new HashMap(), new String[0], null);
+ Response resp = apiClient.getHttpClient().newCall(request).execute();
+ Unknown u = parse(resp.body().byteStream());
+ return (T) builder.mergeFrom(u.getRaw()).build();
+ }
+
+ private Unknown parse(InputStream stream) throws ApiException, IOException {
+ // This isn't really documented anywhere except the code, but
+ // the proto-buf format is:
+ // * 4 byte magic number
+ // * Protocol Buffer encoded object of type runtime.Unknown
+ // * the 'raw' field in that object contains a Protocol Buffer
+ // encoding of the actual object.
+ // TODO: Document this somewhere proper.
+ byte[] magic = new byte[4];
+ stream.read(magic);
+ for (int i = 0; i < MAGIC.length; i++) {
+ if (magic[i] != MAGIC[i]) {
+ throw new ApiException("Unexpected magic number: " + magic);
+ }
+ }
+ return Unknown.parseFrom(stream);
+ }
+}
\ No newline at end of file