org.trustedanalytics.cloud.cc.FeignClient.java Source code

Java tutorial

Introduction

Here is the source code for org.trustedanalytics.cloud.cc.FeignClient.java

Source

/**
 * Copyright (c) 2015 Intel Corporation
 *
 * 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.trustedanalytics.cloud.cc;

import org.trustedanalytics.cloud.cc.api.CcAppEnv;
import org.trustedanalytics.cloud.cc.api.CcAppStatus;
import org.trustedanalytics.cloud.cc.api.CcAppSummary;
import org.trustedanalytics.cloud.cc.api.CcBuildpack;
import org.trustedanalytics.cloud.cc.api.CcExtendedService;
import org.trustedanalytics.cloud.cc.api.CcExtendedServiceInstance;
import org.trustedanalytics.cloud.cc.api.CcExtendedServicePlan;
import org.trustedanalytics.cloud.cc.api.CcMemoryUsage;
import org.trustedanalytics.cloud.cc.api.CcNewServiceBinding;
import org.trustedanalytics.cloud.cc.api.CcNewServiceInstance;
import org.trustedanalytics.cloud.cc.api.CcNewServiceKey;
import org.trustedanalytics.cloud.cc.api.CcOperations;
import org.trustedanalytics.cloud.cc.api.CcOrg;
import org.trustedanalytics.cloud.cc.api.CcOrgPermission;
import org.trustedanalytics.cloud.cc.api.CcOrgSummary;
import org.trustedanalytics.cloud.cc.api.CcPlanVisibility;
import org.trustedanalytics.cloud.cc.api.CcQuota;
import org.trustedanalytics.cloud.cc.api.CcServiceBinding;
import org.trustedanalytics.cloud.cc.api.CcServiceBindingList;
import org.trustedanalytics.cloud.cc.api.CcServiceKey;
import org.trustedanalytics.cloud.cc.api.CcSpace;
import org.trustedanalytics.cloud.cc.api.CcSummary;
import org.trustedanalytics.cloud.cc.api.Page;
import org.trustedanalytics.cloud.cc.api.customizations.CompositeErrorDecoder;
import org.trustedanalytics.cloud.cc.api.customizations.FeignErrorDecoderHandler;
import org.trustedanalytics.cloud.cc.api.loggers.ScramblingSlf4jLogger;
import org.trustedanalytics.cloud.cc.api.manageusers.CcOrgUser;
import org.trustedanalytics.cloud.cc.api.manageusers.CcOrgUsersList;
import org.trustedanalytics.cloud.cc.api.manageusers.CcUser;
import org.trustedanalytics.cloud.cc.api.manageusers.Role;
import org.trustedanalytics.cloud.cc.api.manageusers.User;
import org.trustedanalytics.cloud.cc.api.queries.FilterQuery;
import org.trustedanalytics.cloud.cc.api.resources.CcApplicationResource;
import org.trustedanalytics.cloud.cc.api.resources.CcBuildpacksResource;
import org.trustedanalytics.cloud.cc.api.resources.CcOrganizationResource;
import org.trustedanalytics.cloud.cc.api.resources.CcQuotaResource;
import org.trustedanalytics.cloud.cc.api.resources.CcServiceBindingResource;
import org.trustedanalytics.cloud.cc.api.resources.CcServiceResource;
import org.trustedanalytics.cloud.cc.api.resources.CcSpaceResource;
import org.trustedanalytics.cloud.cc.api.resources.CcUserResource;
import org.trustedanalytics.cloud.cc.api.utils.UuidJsonDeserializer;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy;
import com.google.common.collect.ImmutableMap;

import feign.Feign;
import feign.Feign.Builder;
import feign.Request;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;

import org.apache.commons.lang.StringUtils;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import rx.Observable;

public class FeignClient implements CcOperations {
    private static final Map<Role, String> ROLE_MAP = ImmutableMap.<Role, String>builder()
            .put(Role.MANAGERS, "managed_spaces").put(Role.AUDITORS, "audited_spaces")
            .put(Role.DEVELOPERS, "spaces").build();

    private static final int CONNECT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(30);
    private static final int READ_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(5);

    // We do a lot of delegation here because of https://github.com/Netflix/feign/issues/133
    private final CcApplicationResource applicationResource;
    private final CcOrganizationResource organizationResource;
    private final CcServiceResource serviceResource;
    private final CcServiceBindingResource serviceBindingResource;
    private final CcSpaceResource spaceResource;
    private final CcUserResource userResource;
    private final CcBuildpacksResource buildpackResource;
    private final CcQuotaResource quotaResource;

    /**
     * Creates client applying default configuration
     * @param url endpoint url
     */
    public FeignClient(String url) {
        this(url, Function.identity());
    }

    /**
     * Creates client applying default configuration and then customizations. Example:
     * <pre>
     * {@code
     * new FeignClient(apiUrl, builder -> builder.requestInterceptor(template ->
     * template.header("Authorization", "bearer " + token)));
     * }
     * </pre>
     * @param url endpoint url
     * @param customizations custom configuration that should be applied after defaults
     */
    public FeignClient(String url, Function<Builder, Builder> customizations) {
        Objects.requireNonNull(url);
        Objects.requireNonNull(customizations);

        final ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.setPropertyNamingStrategy(new LowerCaseWithUnderscoresStrategy());

        // avoid duplication of slashes
        final String targetUrl = StringUtils.removeEnd(url, "/");

        // first applies defaults and then custom configuration
        final Builder builder = customizations.apply(Feign.builder().encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder(mapper)).options(new Request.Options(CONNECT_TIMEOUT, READ_TIMEOUT))
                .logger(new ScramblingSlf4jLogger(FeignClient.class)).logLevel(feign.Logger.Level.BASIC)
                .errorDecoder(new CompositeErrorDecoder(new FeignErrorDecoderHandler("description"))));

        this.applicationResource = builder.target(CcApplicationResource.class, targetUrl);
        this.organizationResource = builder.target(CcOrganizationResource.class, targetUrl);
        this.serviceResource = builder.target(CcServiceResource.class, targetUrl);
        this.serviceBindingResource = builder.target(CcServiceBindingResource.class, targetUrl);
        this.spaceResource = builder.target(CcSpaceResource.class, targetUrl);
        this.userResource = builder.target(CcUserResource.class, targetUrl);
        this.buildpackResource = builder.target(CcBuildpacksResource.class, targetUrl);
        this.quotaResource = builder.target(CcQuotaResource.class, targetUrl);
    }

    @Override
    public CcAppSummary getAppSummary(UUID app) {
        return applicationResource.getAppSummary(app);
    }

    @Override
    public void restageApp(UUID appGuid) {
        applicationResource.restageApp(appGuid);
    }

    @Override
    public CcServiceBindingList getAppBindings(UUID app) {
        return applicationResource.getAppBindings(app);
    }

    @Override
    public CcServiceBindingList getAppBindings(UUID app, FilterQuery query) {
        return applicationResource.getAppBindings(app, query);
    }

    @Override
    public void deleteApp(UUID app) {
        applicationResource.deleteApp(app);
    }

    @Override
    public CcServiceBinding createServiceBinding(CcNewServiceBinding ccNewServiceBinding) {
        return serviceBindingResource.createServiceBinding(ccNewServiceBinding);
    }

    @Override
    public void deleteServiceBinding(UUID bindingGuid) {
        serviceBindingResource.deleteServiceBinding(bindingGuid);
    }

    @Override
    public void createUser(UUID userGuid) {
        userResource.createUser(userGuid);
    }

    @Override
    public UUID createOrganization(String orgName) {
        return organizationResource.createOrganization(orgName).getGuid();
    }

    @Override
    public UUID createSpace(UUID orgGuid, String name) {
        return spaceResource.createSpace(orgGuid, name).getGuid();
    }

    @Override
    public void assignUserToOrganization(UUID userGuid, UUID orgGuid) {
        organizationResource.associateUserWithOrganization(orgGuid, userGuid);
        organizationResource.associateManagerWithOrganization(orgGuid, userGuid);
    }

    @Override
    public void assignUserToSpace(UUID userGuid, UUID spaceGuid) {
        spaceResource.associateDeveloperWithSpace(spaceGuid, userGuid);
        spaceResource.associateManagerWithSpace(spaceGuid, userGuid);
    }

    @Override
    public Observable<CcOrg> getOrg(UUID orgUUID) {
        return Observable.defer(() -> Observable.just(organizationResource.getOrganization(orgUUID)));
    }

    @Override
    public Observable<CcOrg> getOrgs() {
        return Observable.defer(() -> concatPages(organizationResource.getOrgs(), organizationResource::getOrgs));
    }

    @Override
    public Observable<CcSpace> getSpaces() {
        return Observable.defer(() -> concatPages(spaceResource.getSpaces(), spaceResource::getSpaces));
    }

    private <T> Observable<T> concatPages(Page<T> page, Function<URI, Page<T>> more) {
        if (page.getNextUrl() == null) {
            return Observable.from(page.getResources());
        } else {
            final URI nextUrl = URI.create(page.getNextUrl());
            return Observable.from(page.getResources())
                    .concatWith(Observable.defer(() -> concatPages(more.apply(nextUrl), more)));
        }
    }

    @Override
    public Observable<CcSpace> getSpace(UUID spaceId) {
        return Observable.defer(() -> Observable.just(spaceResource.getSpace(spaceId)));
    }

    @Override
    public Observable<CcSpace> getSpaces(UUID org) {
        return Observable.defer(
                () -> concatPages(organizationResource.getSpacesForOrganization(org), spaceResource::getSpaces));
    }

    @Override
    public Collection<CcOrg> getManagedOrganizations(UUID user) {
        return userResource.getManagedOrganizations(user).getOrgs();
    }

    @Override
    public Collection<CcOrg> getAuditedOrganizations(UUID user) {
        return userResource.getAuditedOrganizations(user).getOrgs();
    }

    @Override
    public Collection<CcOrg> getBillingManagedOrganizations(UUID user) {
        return userResource.getBillingManagedOrganizations(user).getOrgs();
    }

    @Override
    public void renameOrg(UUID orgId, String name) {
        organizationResource.updateOrganization(orgId, name);
    }

    @Override
    public void deleteOrg(UUID orgGuid) {
        organizationResource.deleteOrganization(orgGuid);
    }

    @Override
    public void deleteSpace(UUID spaceGuid) {
        spaceResource.removeSpace(spaceGuid);
    }

    @Override
    public Collection<CcSpace> getUsersSpaces(UUID userGuid, Role role, FilterQuery filterQuery) {
        return userResource.getUserSpaces(userGuid, ROLE_MAP.get(role), filterQuery).getSpaces();
    }

    @Override
    public Observable<CcExtendedService> getExtendedServices() {
        return Observable.defer(() -> concatPages(serviceResource.getServices(), serviceResource::getServices));
    }

    @Override
    public Observable<CcExtendedService> getExtendedServices(FilterQuery filterQuery) {
        return Observable
                .defer(() -> concatPages(serviceResource.getServices(filterQuery), serviceResource::getServices));
    }

    @Override
    public Observable<CcExtendedServiceInstance> getExtendedServiceInstances() {
        return Observable.defer(() -> concatPages(serviceResource.getExtendedServiceInstances(),
                serviceResource::getExtendedServiceInstances));
    }

    @Override
    public Observable<CcExtendedServiceInstance> getExtendedServiceInstances(FilterQuery filterQuery) {
        return Observable.defer(() -> concatPages(serviceResource.getExtendedServiceInstances(filterQuery),
                serviceResource::getExtendedServiceInstances));
    }

    @Override
    public Observable<CcExtendedServiceInstance> getExtendedServiceInstances(int depth) {
        return Observable.defer(() -> concatPages(serviceResource.getExtendedServiceInstances(depth),
                serviceResource::getExtendedServiceInstances));
    }

    @Override
    public Observable<CcExtendedServiceInstance> getExtendedServiceInstances(FilterQuery filterQuery, int depth) {
        return Observable.defer(() -> concatPages(serviceResource.getExtendedServiceInstances(filterQuery, depth),
                serviceResource::getExtendedServiceInstances));
    }

    @Override
    public Observable<CcExtendedServicePlan> getExtendedServicePlans(UUID serviceGuid) {
        return Observable.defer(() -> concatPages(serviceResource.getExtendedServicePlans(serviceGuid),
                serviceResource::getExtendedServicePlans));
    }

    @Override
    public Observable<CcExtendedServicePlan> getExtendedServicePlan(UUID servicePlanGuid) {
        return Observable.defer(() -> Observable.just(serviceResource.getExtendedServicePlan(servicePlanGuid)));
    }

    @Override
    public Observable<CcExtendedService> getServices(UUID spaceGuid) {
        return Observable
                .defer(() -> concatPages(spaceResource.getServices(spaceGuid), spaceResource::getServices));
    }

    @Override
    public Observable<CcExtendedService> getOrganizationServices(UUID orgGuid) {
        return Observable.defer(() -> concatPages(organizationResource.getOrganizationServices(orgGuid),
                organizationResource::getOrganizationServices));
    }

    @Override
    public Observable<CcExtendedService> getService(UUID serviceGuid) {
        return Observable.defer(() -> Observable.just(serviceResource.getService(serviceGuid)));
    }

    @Override
    public CcServiceBindingList getServiceBindings(FilterQuery filterQuery) {
        return serviceBindingResource.getServiceBindings(filterQuery);
    }

    @Override
    public Observable<CcServiceKey> getServiceKeys() {
        return Observable
                .defer(() -> concatPages(serviceResource.getServiceKeys(), serviceResource::getServiceKeys));
    }

    @Override
    public Observable<CcServiceKey> createServiceKey(CcNewServiceKey serviceKey) {
        return Observable.defer(() -> Observable.just(serviceResource.createServiceKey(serviceKey)));
    }

    @Override
    public void deleteServiceKey(UUID keyGuid) {
        serviceResource.deleteServiceKey(keyGuid);
    }

    @Override
    public Observable<CcPlanVisibility> setExtendedServicePlanVisibility(UUID servicePlanGuid,
            UUID organizationGuid) {
        return Observable.defer(
                () -> Observable.just(serviceResource.setServicePlanVisibility(servicePlanGuid, organizationGuid)));
    }

    @Override
    public Observable<CcPlanVisibility> getExtendedServicePlanVisibility(FilterQuery filterQuery) {
        return Observable.defer(() -> concatPages(serviceResource.getServicePlanVisibility(filterQuery),
                serviceResource::getServicePlanVisibility));
    }

    @Override
    public Observable<CcExtendedServiceInstance> getServiceInstance(UUID instanceGuid) {
        return Observable.defer(() -> Observable.just(serviceResource.getServiceInstance(instanceGuid)));
    }

    @Override
    public Observable<CcExtendedServiceInstance> createServiceInstance(CcNewServiceInstance serviceInstance) {
        return Observable.defer(() -> Observable.just(serviceResource.createServiceInstance(serviceInstance)));
    }

    @Override
    public void deleteServiceInstance(UUID instanceGuid) {
        serviceResource.deleteServiceInstance(instanceGuid);
    }

    @Override
    public CcSummary getSpaceSummary(UUID spaceGuid) {
        return spaceResource.getSpaceSummary(spaceGuid);
    }

    @Override
    public Collection<CcOrg> getUserOrgs(UUID userGuid) {
        return userResource.getUserOrganizations(userGuid).getOrgs();
    }

    @Override
    public Collection<CcOrgPermission> getUserPermissions(UUID user, Collection<UUID> orgsFilter) {
        Collection<CcOrg> orgs = userResource.getUserOrganizations(user).getOrgs();

        if (!orgsFilter.isEmpty()) {
            orgs.removeIf(ccOrg -> !orgsFilter.contains(ccOrg.getGuid()));
        }

        Collection<CcOrg> managedOrganizations = getManagedOrganizations(user);
        Collection<CcOrg> auditedOrganizations = getAuditedOrganizations(user);
        Collection<CcOrg> billingManagedOrganizations = getBillingManagedOrganizations(user);

        Collection<CcOrgPermission> permissions = new ArrayList<>();
        orgs.forEach(org -> {
            boolean isManager = managedOrganizations.contains(org);
            boolean isAuditor = auditedOrganizations.contains(org);
            boolean isBillingManager = billingManagedOrganizations.contains(org);
            permissions.add(new CcOrgPermission(org, isManager, isAuditor, isBillingManager));
        });

        return permissions;
    }

    @Override
    public Collection<User> getOrgUsers(UUID orgGuid, Role role) {
        return toUsers(Observable
                .defer(() -> concatPages(organizationResource.getOrganizationUsers(orgGuid, role.getValue()),
                        organizationResource::getOrganizationUsers)),
                role);
    }

    @Override
    public Collection<User> getSpaceUsers(UUID spaceGuid, Role role) {
        return toUsers(spaceResource.getSpaceUsers(spaceGuid, role.getValue()), role);
    }

    @Override
    public Observable<User> getSpaceUsersWithRoles(UUID spaceGuid) {
        return Observable
                .defer(() -> concatPages(spaceResource.getSpaceUsersWithRoles(spaceGuid),
                        spaceResource::getSpaceUsersWithRoles))
                .map(ccOrgUser -> new User(ccOrgUser.getUsername(), ccOrgUser.getGuid(), ccOrgUser.getRoles()));
    }

    @Override
    public Observable<User> getOrgUsersWithRoles(UUID orgGuid) {
        return Observable
                .defer(() -> concatPages(organizationResource.getOrganizationUsersWithRoles(orgGuid),
                        organizationResource::getOrganizationUsersWithRoles))
                .map(ccOrgUser -> new User(ccOrgUser.getUsername(), ccOrgUser.getGuid(), ccOrgUser.getRoles()));
    }

    @Override
    public void assignOrgRole(UUID userGuid, UUID orgGuid, Role role) {
        organizationResource.associateUserWithOrganizationRole(orgGuid, userGuid, role.getValue());
    }

    @Override
    public void assignSpaceRole(UUID userGuid, UUID orgGuid, Role role) {
        spaceResource.associateUserWithSpaceRole(orgGuid, userGuid, role.getValue());
    }

    @Override
    public void deleteUser(UUID guid) {
        userResource.deleteUser(guid);
    }

    @Override
    public void revokeOrgRole(UUID userGuid, UUID orgId, Role role) {
        organizationResource.removeOrganizationRoleFromUser(orgId, userGuid, role.getValue());
    }

    @Override
    public void revokeSpaceRole(UUID userGuid, UUID spaceId, Role role) {
        spaceResource.removeSpaceRoleFromUser(spaceId, userGuid, role.getValue());
    }

    private Collection<User> toUsers(CcOrgUsersList ccUsers, Role role) {
        return ccUsers.getUsers().stream().map(ccUser -> new User(ccUser.getUsername(), ccUser.getGuid(), role))
                .collect(Collectors.toList());
    }

    private Collection<User> toUsers(Observable<CcOrgUser> ccUsers, Role role) {
        return ccUsers.map(ccUser -> new User(ccUser.getUsername(), ccUser.getGuid(), role)).toList().toBlocking()
                .first();
    }

    @Override
    public void switchApp(UUID app, CcAppStatus appStatus) {
        applicationResource.switchApp(app, appStatus);
    }

    @Override
    public Observable<CcAppEnv> getAppEnv(UUID appUUID) {
        return Observable.defer(() -> Observable.just(new CcAppEnv(applicationResource.getAppEnv(appUUID))));
    }

    @Override
    public Observable<CcMemoryUsage> getMemoryUsage(UUID orgGuid) {
        return Observable.defer(() -> Observable.just(organizationResource.getMemoryUsage(orgGuid)));
    }

    @Override
    public Observable<CcQuota> getQuota() {
        return Observable.defer(() -> concatPages(quotaResource.getQuota(), quotaResource::getQuota));
    }

    @Override
    public Observable<CcBuildpack> getBuildpacks() {
        return Observable
                .defer(() -> concatPages(buildpackResource.getBuildpacks(), buildpackResource::getBuildpacks));
    }

    @Override
    public Observable<CcOrgSummary> getOrgSummary(UUID orgGuid) {
        return Observable.defer(() -> Observable.just(organizationResource.getOrganizationSummary(orgGuid)));
    }

    @Override
    public Observable<CcUser> getUsers() {
        return Observable.defer(() -> concatPages(userResource.getUsers(), userResource::getUsers)
                .filter(user -> !user.getMetadata().getGuid().equals(UuidJsonDeserializer.ARTIFICIAL_USER_GUID)));
    }

    @Override
    public Observable<Integer> getUsersCount() {
        return Observable.defer(() -> Observable.just(userResource.getUsersCount().getTotalResults()));
    }

    @Override
    public Observable<Integer> getServicesCount() {
        return Observable.defer(() -> Observable.just(serviceResource.getServices().getTotalResults()));
    }

    @Override
    public Observable<Integer> getServiceInstancesCount() {
        return Observable
                .defer(() -> Observable.just(serviceResource.getExtendedServiceInstances().getTotalResults()));
    }

    @Override
    public Observable<Integer> getApplicationsCount() {
        return Observable.defer(() -> Observable.just(applicationResource.getApplications().getTotalResults()));
    }

    @Override
    public Observable<Integer> getBuildpacksCount() {
        return Observable.defer(() -> Observable.just(buildpackResource.getBuildpacks().getTotalResults()));
    }

    @Override
    public Observable<Integer> getSpacesCount() {
        return Observable.defer(() -> Observable.just(spaceResource.getSpaces().getTotalResults()));
    }

    @Override
    public Observable<Integer> getOrgsCount() {
        return Observable.defer(() -> Observable.just(organizationResource.getOrgs().getTotalResults()));
    }

}