All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.pulsar.client.admin.internal.PackagesImpl Maven / Gradle / Ivy

There is a newer version: 4.0.0-preview.1
Show newest version
/*
 * 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.pulsar.client.admin.internal;

import static org.apache.pulsar.shade.org.asynchttpclient.Dsl.get;
import org.apache.pulsar.shade.com.google.gson.Gson;
import org.apache.pulsar.shade.io.netty.handler.codec.http.HttpHeaders;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.apache.pulsar.shade.javax.ws.rs.client.Entity;
import org.apache.pulsar.shade.javax.ws.rs.client.WebTarget;
import org.apache.pulsar.shade.javax.ws.rs.core.MediaType;
import org.apache.pulsar.shade.javax.ws.rs.core.Response;
import org.apache.pulsar.client.admin.Packages;
import org.apache.pulsar.client.admin.PulsarAdminException;
import org.apache.pulsar.client.api.Authentication;
import org.apache.pulsar.common.naming.NamespaceName;
import org.apache.pulsar.packages.management.core.common.PackageMetadata;
import org.apache.pulsar.packages.management.core.common.PackageName;
import org.apache.pulsar.shade.org.asynchttpclient.AsyncHandler;
import org.apache.pulsar.shade.org.asynchttpclient.AsyncHttpClient;
import org.apache.pulsar.shade.org.asynchttpclient.Dsl;
import org.apache.pulsar.shade.org.asynchttpclient.HttpResponseBodyPart;
import org.apache.pulsar.shade.org.asynchttpclient.HttpResponseStatus;
import org.apache.pulsar.shade.org.asynchttpclient.RequestBuilder;
import org.apache.pulsar.shade.org.asynchttpclient.request.body.multipart.FilePart;
import org.apache.pulsar.shade.org.asynchttpclient.request.body.multipart.StringPart;

/**
 * The implementation of the packages management service administration operations.
 */
public class PackagesImpl extends ComponentResource implements Packages {

    private final WebTarget packages;
    private final AsyncHttpClient httpClient;

    public PackagesImpl(WebTarget webTarget, Authentication auth, AsyncHttpClient client, long readTimeoutMs) {
        super(auth, readTimeoutMs);
        this.httpClient = client;
        this.packages = webTarget.path("/admin/v3/packages");
    }

    @Override
    public PackageMetadata getMetadata(String packageName) throws PulsarAdminException {
        return sync(() -> getMetadataAsync(packageName));
    }

    @Override
    public CompletableFuture getMetadataAsync(String packageName) {
        WebTarget path = packages.path(PackageName.get(packageName).toRestPath() + "/metadata");
        return asyncGetRequest(path, new FutureCallback(){});
    }

    @Override
    public void updateMetadata(String packageName, PackageMetadata metadata) throws PulsarAdminException {
        sync(() -> updateMetadataAsync(packageName, metadata));
    }

    @Override
    public CompletableFuture updateMetadataAsync(String packageName, PackageMetadata metadata) {
        WebTarget path = packages.path(PackageName.get(packageName).toRestPath() + "/metadata");
        return asyncPutRequest(path, Entity.entity(metadata, MediaType.APPLICATION_JSON));
    }

    @Override
    public void upload(PackageMetadata metadata, String packageName, String path) throws PulsarAdminException {
        sync(() -> uploadAsync(metadata, packageName, path));
    }

    @Override
    public CompletableFuture uploadAsync(PackageMetadata metadata, String packageName, String path) {
        final CompletableFuture future = new CompletableFuture<>();
        try {
            RequestBuilder builder = Dsl
                .post(packages.path(PackageName.get(packageName).toRestPath()).getUri().toASCIIString())
                .addBodyPart(new FilePart("file", new File(path), MediaType.APPLICATION_OCTET_STREAM))
                .addBodyPart(new StringPart("metadata", new Gson().toJson(metadata), MediaType.APPLICATION_JSON));
            httpClient.executeRequest(addAuthHeaders(packages, builder).build())
                .toCompletableFuture()
                .thenAccept(response -> {
                    if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
                        future.completeExceptionally(
                            getApiException(Response
                                .status(response.getStatusCode())
                                .entity(response.getResponseBody())
                                .build()));
                    } else {
                        future.complete(null);
                    }
                })
                .exceptionally(throwable -> {
                    future.completeExceptionally(getApiException(throwable));
                    return null;
                });
        } catch (PulsarAdminException e) {
            future.completeExceptionally(e);
        }
        return future;    }

    @Override
    public void download(String packageName, String path) throws PulsarAdminException {
        sync(() -> downloadAsync(packageName, path));
    }

    @Override
    public CompletableFuture downloadAsync(String packageName, String path) {
        WebTarget webTarget = packages.path(PackageName.get(packageName).toRestPath());
        final CompletableFuture future = new CompletableFuture<>();
        try {
            Path destinyPath = Paths.get(path);
            if (destinyPath.getParent() != null) {
                Files.createDirectories(destinyPath.getParent());
            }

            FileChannel os = new FileOutputStream(destinyPath.toFile()).getChannel();
            RequestBuilder builder = get(webTarget.getUri().toASCIIString());

            CompletableFuture statusFuture =
                httpClient.executeRequest(addAuthHeaders(webTarget, builder).build(),
                    new AsyncHandler() {
                        private HttpResponseStatus status;

                        @Override
                        public State onStatusReceived(HttpResponseStatus httpResponseStatus) throws Exception {
                            status = httpResponseStatus;
                            if (status.getStatusCode() != Response.Status.OK.getStatusCode()) {
                                return State.ABORT;
                            }
                            return State.CONTINUE;
                        }

                        @Override
                        public State onHeadersReceived(HttpHeaders httpHeaders) throws Exception {
                            return State.CONTINUE;
                        }

                        @Override
                        public State onBodyPartReceived(HttpResponseBodyPart httpResponseBodyPart) throws Exception {
                            os.write(httpResponseBodyPart.getBodyByteBuffer());
                            return State.CONTINUE;
                        }

                        @Override
                        public void onThrowable(Throwable throwable) {
                            // we don't need to handle that throwable and use the returned future to handle it.
                        }

                        @Override
                        public HttpResponseStatus onCompleted() throws Exception {
                            return status;
                        }
                    }).toCompletableFuture();
            statusFuture
                .whenComplete((status, throwable) -> {
                    try {
                        os.close();
                    } catch (IOException e) {
                        future.completeExceptionally(getApiException(throwable));
                    }
                })
                .thenAccept(status -> {
                    if (status.getStatusCode() < 200 || status.getStatusCode() >= 300) {
                        future.completeExceptionally(
                            getApiException(Response
                                .status(status.getStatusCode())
                                .entity(status.getStatusText())
                                .build()));
                    } else {
                        future.complete(null);
                    }
                })
                .exceptionally(throwable -> {
                    future.completeExceptionally(getApiException(throwable));
                    return null;
                });
        } catch (Exception e) {
            future.completeExceptionally(getApiException(e));
        }
        return future;
    }

    @Override
    public void delete(String packageName) throws PulsarAdminException {
        sync(() -> deleteAsync(packageName));
    }

    @Override
    public CompletableFuture deleteAsync(String packageName) {
        PackageName name = PackageName.get(packageName);
        WebTarget path = packages.path(name.toRestPath());
        return asyncDeleteRequest(path);
    }

    @Override
    public List listPackageVersions(String packageName) throws PulsarAdminException {
        return sync(() -> listPackageVersionsAsync(packageName));
    }


    @Override
    public CompletableFuture> listPackageVersionsAsync(String packageName) {
        PackageName name = PackageName.get(packageName);
        WebTarget path = packages.path(String.format("%s/%s/%s/%s",
            name.getPkgType().toString(), name.getTenant(), name.getNamespace(), name.getName()));
        return asyncGetRequest(path, new FutureCallback>(){});
    }

    @Override
    public List listPackages(String type, String namespace) throws PulsarAdminException {
        return sync(() -> listPackagesAsync(type, namespace));
    }

    @Override
    public CompletableFuture> listPackagesAsync(String type, String namespace) {
        WebTarget path = packages.path(type + "/" + NamespaceName.get(namespace).toString());
        return asyncGetRequest(path, new FutureCallback>(){});
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy