io.fabric8.kubernetes.client.dsl.internal.LogWatchCallback Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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.fabric8.kubernetes.client.dsl.internal;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.LogWatch;
import io.fabric8.kubernetes.client.http.AsyncBody;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.http.HttpRequest;
import io.fabric8.kubernetes.client.utils.internal.SerialExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
public class LogWatchCallback implements LogWatch, AutoCloseable {
private static final Logger LOGGER = LoggerFactory.getLogger(LogWatchCallback.class);
private final OutputStream out;
private WritableByteChannel outChannel;
private volatile InputStream output;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final CompletableFuture asyncBody = new CompletableFuture<>();
private final SerialExecutor serialExecutor;
public LogWatchCallback(OutputStream out, OperationContext context) {
this.out = out;
if (out != null) {
outChannel = Channels.newChannel(out);
}
this.serialExecutor = new SerialExecutor(context.getExecutor());
}
@Override
public void close() {
cleanUp();
}
private void cleanUp() {
if (!closed.compareAndSet(false, true)) {
return;
}
asyncBody.thenAccept(AsyncBody::cancel);
serialExecutor.shutdownNow();
}
public LogWatchCallback callAndWait(HttpClient client, URL url) {
HttpRequest request = client.newHttpRequestBuilder().url(url).build();
if (out == null) {
// we can pass the input stream directly to the consumer
client.sendAsync(request, InputStream.class).whenComplete((r, e) -> {
if (e != null) {
onFailure(e);
}
if (r != null) {
this.output = r.body();
}
}).join();
} else {
// we need to write the bytes to the given output
// we don't know if the write will be blocking, so hand it off to another thread
client.consumeBytes(request, (buffers, a) -> CompletableFuture.runAsync(() -> {
for (ByteBuffer byteBuffer : buffers) {
try {
outChannel.write(byteBuffer);
} catch (IOException e1) {
throw KubernetesClientException.launderThrowable(e1);
}
}
}, serialExecutor).whenComplete((v, t) -> {
if (t != null) {
a.cancel();
onFailure(t);
} else if (!closed.get()) {
a.consume();
} else {
a.cancel();
}
})).whenComplete((a, e) -> {
if (e != null) {
onFailure(e);
}
if (a != null) {
asyncBody.complete(a.body());
a.body().consume();
a.body().done().whenComplete((v, t) -> CompletableFuture.runAsync(() -> {
if (t != null) {
onFailure(t);
} else {
cleanUp();
}
}, serialExecutor));
}
});
}
return this;
}
@Override
public InputStream getOutput() {
return output;
}
public void onFailure(Throwable u) {
//If we have closed the watch ignore everything
if (closed.get()) {
return;
}
LOGGER.error("Log Callback Failure.", u);
cleanUp();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy