org.cloudfoundry.util.ResourceMatchingUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.util.ResourceMatchingUtils.java

Source

/*
 * Copyright 2013-2017 the original author or 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 org.cloudfoundry.util;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.resourcematch.ListMatchingResourcesRequest;
import org.cloudfoundry.client.v2.resourcematch.ListMatchingResourcesResponse;
import org.cloudfoundry.client.v2.resourcematch.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;

/**
 * Utilities for matching resources
 */
public final class ResourceMatchingUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger("cloudfoundry-client.resource-matching");

    private ResourceMatchingUtils() {
    }

    public static Mono<List<ArtifactMetadata>> getMatchedResources(CloudFoundryClient cloudFoundryClient,
            Path application) {
        return (Files.isDirectory(application) ? getArtifactMetadataFromDirectory(application)
                : getArtifactMetadataFromZip(application))
                        .collectMap(ArtifactMetadata::getHash)
                        .flatMapMany(artifactMetadatas -> requestListMatchingResources(cloudFoundryClient,
                                artifactMetadatas.values())
                                        .flatMapIterable(ListMatchingResourcesResponse::getResources)
                                        .map(resource -> artifactMetadatas.get(resource.getHash())))
                        .collectList()
                        .doOnNext(matched -> LOGGER.debug("{} resources matched totaling {}", matched.size(),
                                SizeUtils.asIbi(matched.stream().mapToInt(ArtifactMetadata::getSize).sum())))
                        .subscribeOn(Schedulers.elastic());
    }

    private static Flux<ArtifactMetadata> getArtifactMetadataFromDirectory(Path application) {
        return Flux.defer(() -> {
            try {
                return Flux.fromStream(Files.walk(application));
            } catch (IOException e) {
                throw Exceptions.propagate(e);
            }
        }).filter(path -> !Files.isDirectory(path))
                .map(path -> new ArtifactMetadata(FileUtils.hash(path),
                        FileUtils.getRelativePathName(application, path), FileUtils.permissions(path),
                        FileUtils.size(path)));
    }

    private static Flux<ArtifactMetadata> getArtifactMetadataFromZip(Path application) {
        List<ArtifactMetadata> artifactMetadatas = new ArrayList<>();

        try (ZipFile zipFile = new ZipFile(application.toFile())) {
            Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();

            while (entries.hasMoreElements()) {
                ZipArchiveEntry entry = entries.nextElement();

                if (!entry.isDirectory()) {
                    try (InputStream in = zipFile.getInputStream(entry)) {
                        String hash = FileUtils.hash(in);
                        String path = entry.getName();
                        String permissions = FileUtils.permissions(entry.getUnixMode());
                        int size = (int) entry.getSize();

                        artifactMetadatas.add(new ArtifactMetadata(hash, path, permissions, size));
                    }

                }
            }
        } catch (IOException e) {
            throw Exceptions.propagate(e);
        }

        return Flux.fromIterable(artifactMetadatas);
    }

    private static Mono<ListMatchingResourcesResponse> requestListMatchingResources(
            CloudFoundryClient cloudFoundryClient, Collection<ArtifactMetadata> artifactMetadatas) {
        ListMatchingResourcesRequest request = artifactMetadatas.stream()
                .reduce(ListMatchingResourcesRequest.builder(), (builder,
                        artifactMetadata) -> builder.resource(Resource.builder().hash(artifactMetadata.getHash())
                                .mode(artifactMetadata.getPermissions()).size(artifactMetadata.getSize()).build()),
                        (a, b) -> a.addAllResources(b.build().getResources()))
                .build();

        return cloudFoundryClient.resourceMatch().list(request);
    }

    /**
     * Metadata information about a given artifact
     */
    public static final class ArtifactMetadata {

        private final String hash;

        private final String path;

        private final String permissions;

        private final int size;

        /**
         * Creates a new instance
         *
         * @param hash        the SHA-1 hash of the artifact
         * @param path        the relative path of the artifact
         * @param permissions the UNIX permissions of the artifact
         * @param size        the size of the artifact
         */
        public ArtifactMetadata(String hash, String path, String permissions, int size) {
            this.hash = hash;
            this.path = path;
            this.permissions = permissions;
            this.size = size;
        }

        /**
         * Returns the SHA-1 hash of the artifact
         *
         * @return the SHA-1 hash of the artifact
         */
        public String getHash() {
            return this.hash;
        }

        /**
         * Returns the path of the artifact
         *
         * @return the path of the artifact
         */
        public String getPath() {
            return this.path;
        }

        /**
         * Returns the permissions of the artifact
         *
         * @return the permissions of the artifact
         */
        public String getPermissions() {
            return this.permissions;
        }

        /**
         * Returns the size of the artifact
         *
         * @return the size of the artifact
         */
        public int getSize() {
            return this.size;
        }

    }

}