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

io.gravitee.management.service.impl.SubscriptionServiceImpl Maven / Gradle / Ivy

There is a newer version: 1.30.31
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.gravitee.management.service.impl;

import com.google.common.collect.ImmutableMap;
import io.gravitee.common.utils.UUID;
import io.gravitee.management.model.*;
import io.gravitee.management.service.*;
import io.gravitee.management.service.builder.EmailNotificationBuilder;
import io.gravitee.management.service.exceptions.*;
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.SubscriptionRepository;
import io.gravitee.repository.management.model.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.Date;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author David BRASSELY (david.brassely at graviteesource.com)
 * @author GraviteeSource Team
 */
@Component
public class SubscriptionServiceImpl extends AbstractService implements SubscriptionService {

    /**
     * Logger.
     */
    private final Logger LOGGER = LoggerFactory.getLogger(SubscriptionServiceImpl.class);

    private final static String SUBSCRIPTION_SYSTEM_VALIDATOR = "system";

    @Autowired
    private PlanService planService;

    @Autowired
    private SubscriptionRepository subscriptionRepository;

    @Autowired
    private ApiKeyService apiKeyService;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ApiService apiService;

    @Autowired
    private EmailService emailService;

    @Override
    public SubscriptionEntity findById(String subscription) {
        try {
            LOGGER.debug("Find subscription by id : {}", subscription);

            Optional optSubscription = subscriptionRepository.findById(subscription);

            if (! optSubscription.isPresent()) {
                throw new SubscriptionNotFoundException(subscription);
            }

            return convert(optSubscription.get());
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to find a subscription using its ID: {}", subscription, ex);
            throw new TechnicalManagementException(
                    String.format("An error occurs while trying to find a subscription using its ID: %s", subscription), ex);
        }
    }

    @Override
    public Set findByApplicationAndPlan(String application, String plan) {
        try {
            LOGGER.debug("Find subscriptions by application {} and plan {}", application, plan);

            Set subscriptions = null;

            if (application != null && ! application.trim().isEmpty()) {
                subscriptions = subscriptionRepository.findByApplication(application);
            } else if (isAuthenticated()){
                Set applications = applicationService.findByUser(getAuthenticatedUsername());
                subscriptions = applications.stream().flatMap(new Function>() {
                    @Override
                    public Stream apply(ApplicationEntity applicationEntity) {
                        try {
                            return subscriptionRepository.findByApplication(applicationEntity.getId()).stream();
                        } catch (TechnicalException e) {
                            e.printStackTrace();
                        }
                        return Stream.empty();
                    }
                }).collect(Collectors.toSet());
            }

            if (subscriptions != null) {
                return subscriptions
                        .stream()
                        .filter(subscription -> plan == null || plan.equals(subscription.getPlan()))
                        .map(this::convert)
                        .collect(Collectors.toSet());
            }

            return Collections.emptySet();
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to find subscriptions by application: {}", application, ex);
            throw new TechnicalManagementException(
                    String.format("An error occurs while trying to find subscriptions by application: %s", application), ex);
        }
    }

    @Override
    public Set findByApi(String api) {
        LOGGER.debug("Find subscriptions by api {}", api);

        Set plans = planService.findByApi(api);
        Set subscriptions = plans.stream().flatMap(plan -> {
            try {
                return subscriptionRepository.findByPlan(plan.getId()).stream();
            } catch (TechnicalException te) {
                LOGGER.error("An error occurs while searching for subscriptions by plan: {}", plan.getId(), te);
            }
            return Stream.empty();
        }).collect(Collectors.toSet());

        if (subscriptions != null) {
            return subscriptions
                    .stream()
                    .map(this::convert)
                    .collect(Collectors.toSet());
        }

        return Collections.emptySet();
    }

    @Override
    public Set findByPlan(String plan) {
        try {
            LOGGER.debug("Find subscriptions by plan : {}", plan);
            Set subscriptions = subscriptionRepository.findByPlan(plan);
            return subscriptions.stream().map(this::convert).collect(Collectors.toSet());
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to find subscriptions by plan: {}", plan, ex);
            throw new TechnicalManagementException(
                    String.format("An error occurs while trying to find subscriptions by plan: %s", plan), ex);
        }
    }

    @Override
    public SubscriptionEntity create(String plan, String application) {
        try {
            LOGGER.debug("Create a new subscription for plan {} and application {}", plan, application);

            PlanEntity planEntity = planService.findById(plan);
            ApplicationEntity applicationEntity = applicationService.findById(application);

            long subscriptionCount = subscriptionRepository.findByApplication(application)
                    .stream()
                    .filter(subscription ->
                            subscription.getPlan().equals(plan) &&
                                    subscription.getStatus() != Subscription.Status.REJECTED)
                    .count();

            if (subscriptionCount > 0) {
                throw new PlanAlreadySubscribedException(plan);
            }

            Subscription subscription = new Subscription();
            subscription.setPlan(plan);
            subscription.setId(UUID.toString(UUID.random()));
            subscription.setApplication(application);
            subscription.setCreatedAt(new Date());
            subscription.setUpdatedAt(subscription.getCreatedAt());
            subscription.setStatus(Subscription.Status.PENDING);
            subscription.setSubscribedBy(getAuthenticatedUser().getUsername());

            subscription = subscriptionRepository.create(subscription);

            final ApiEntity api = apiService.findById(planEntity.getApis().iterator().next());
            final PrimaryOwnerEntity apiOwner = api.getPrimaryOwner();
            final PrimaryOwnerEntity appOwner = applicationEntity.getPrimaryOwner();

            // Send a notification to the primary owner of the API
            if (apiOwner != null && apiOwner.getEmail() != null && !apiOwner.getEmail().isEmpty()) {
                emailService.sendEmailNotification(new EmailNotificationBuilder()
                        .to(apiOwner.getEmail())
                        .subject("New subscription for " + api.getName() + " with plan " + planEntity.getName())
                        .template(EmailNotificationBuilder.EmailTemplate.NEW_SUBSCRIPTION)
                        .params(ImmutableMap.of(
                                "owner", appOwner,
                                "api", api,
                                "plan", plan,
                                "application", application))
                        .build());
            }

            if (PlanValidationType.AUTO == planEntity.getValidation()) {
                ProcessSubscriptionEntity process = new ProcessSubscriptionEntity();
                process.setId(subscription.getId());
                process.setAccepted(true);
                process.setStartingAt(new Date());

                // Do process
                process(process, SUBSCRIPTION_SYSTEM_VALIDATOR);
            }

            return convert(subscription);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to subscribe to the plan {}", plan, ex);
            throw new TechnicalManagementException(String.format(
                    "An error occurs while trying to subscribe to the plan %s", plan), ex);
        }
    }

    @Override
    public SubscriptionEntity update(UpdateSubscriptionEntity updateSubscription) {
        try {
            LOGGER.debug("Update subscription {}", updateSubscription.getId());

            Optional optSubscription = subscriptionRepository.findById(updateSubscription.getId());
            if (! optSubscription.isPresent()) {
                throw new SubscriptionNotFoundException(updateSubscription.getId());
            }

            Subscription subscription = optSubscription.get();

            if (subscription.getStatus() == Subscription.Status.ACCEPTED) {
                subscription.setUpdatedAt(new Date());
                subscription.setStartingAt(updateSubscription.getStartingAt());
                subscription.setEndingAt(updateSubscription.getEndingAt());

                subscription = subscriptionRepository.update(subscription);

                // Update the expiration date for not yet revoked api-keys relative to this subscription
                Date endingAt = subscription.getEndingAt();
                if (endingAt != null) {

                    Set apiKeys = apiKeyService.findBySubscription(subscription.getId());
                    Date now = new Date();
                    for (ApiKeyEntity apiKey : apiKeys) {
                        Date expireAt = apiKey.getExpireAt();
                        if (!apiKey.isRevoked() && (expireAt == null || expireAt.equals(now) || expireAt.before(now))) {
                            apiKey.setExpireAt(endingAt);
                            apiKeyService.update(apiKey);
                        }
                    }
                }

                return convert(subscription);
            }

            throw new SubscriptionNotUpdatableException(updateSubscription.getId());
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to update subscription {}", updateSubscription.getId(), ex);
            throw new TechnicalManagementException(String.format(
                    "An error occurs while trying to update subscription %s", updateSubscription.getId()), ex);
        }
    }

    @Override
    public SubscriptionEntity process(ProcessSubscriptionEntity processSubscription, String validator) {
        try {
            LOGGER.debug("Subscription {} processed by {}", processSubscription.getId(), validator);

            Optional optSubscription = subscriptionRepository.findById(processSubscription.getId());
            if (! optSubscription.isPresent()) {
                throw new SubscriptionNotFoundException(processSubscription.getId());
            }

            Subscription subscription = optSubscription.get();

            if (subscription.getStatus() != Subscription.Status.PENDING) {
                throw new SubscriptionAlreadyProcessedException(subscription.getId());
            }

            subscription.setProcessedBy(validator);
            subscription.setProcessedAt(new Date());

            if (processSubscription.isAccepted()) {
                subscription.setStatus(Subscription.Status.ACCEPTED);
                subscription.setStartingAt((processSubscription.getStartingAt() != null) ?
                        processSubscription.getStartingAt() : new Date());
                subscription.setEndingAt(processSubscription.getEndingAt());
            } else {
                subscription.setStatus(Subscription.Status.REJECTED);
                subscription.setReason(processSubscription.getReason());
            }

            subscription = subscriptionRepository.update(subscription);

            final ApplicationEntity application = applicationService.findById(subscription.getApplication());
            final PlanEntity plan = planService.findById(subscription.getPlan());
            final ApiEntity api = apiService.findById(plan.getApis().iterator().next());
            final PrimaryOwnerEntity owner = application.getPrimaryOwner();

            if (owner != null && owner.getEmail() != null && !owner.getEmail().isEmpty()) {
                if (subscription.getStatus() == Subscription.Status.ACCEPTED) {
                    emailService.sendEmailNotification(new EmailNotificationBuilder()
                            .to(owner.getEmail())
                            .subject("Your subscription to " + api.getName() + " with plan " + plan.getName() +
                                    " has been approved")
                            .template(EmailNotificationBuilder.EmailTemplate.APPROVE_SUBSCRIPTION)
                            .params(ImmutableMap.of(
                                    "owner", owner,
                                    "api", api,
                                    "plan", plan,
                                    "application", application))
                            .build());
                } else {
                    emailService.sendEmailNotification(new EmailNotificationBuilder()
                            .to(owner.getEmail())
                            .subject("Your subscription to " + api.getName() + " with plan " + plan.getName() +
                                    " has been rejected")
                            .template(EmailNotificationBuilder.EmailTemplate.REJECT_SUBSCRIPTION)
                            .params(ImmutableMap.of(
                                    "owner", owner,
                                    "api", api,
                                    "plan", plan,
                                    "application", application))
                            .build());
                }
            }

            if (subscription.getStatus() == Subscription.Status.ACCEPTED) {
                apiKeyService.generate(subscription.getId());
            }

            return convert(subscription);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to process subscription {} by {}",
                    processSubscription.getId(), validator, ex);
            throw new TechnicalManagementException(String.format(
                    "An error occurs while trying to process subscription %s by %s",
                    processSubscription.getId(), validator), ex);
        }
    }

    @Override
    public SubscriptionEntity close(String subscriptionId) {
        try {
            LOGGER.debug("Close subscription {}", subscriptionId);

            Optional optSubscription = subscriptionRepository.findById(subscriptionId);
            if (! optSubscription.isPresent()) {
                throw new SubscriptionNotFoundException(subscriptionId);
            }

            Subscription subscription = optSubscription.get();

            if (subscription.getStatus() == Subscription.Status.ACCEPTED) {
                subscription.setUpdatedAt(new Date());
                subscription.setStatus(Subscription.Status.CLOSED);

                subscription = subscriptionRepository.update(subscription);

                // API Keys are automatically revoked
                Date endingAt = subscription.getEndingAt();
                if (endingAt != null) {

                    Set apiKeys = apiKeyService.findBySubscription(subscription.getId());
                    Date now = new Date();
                    for (ApiKeyEntity apiKey : apiKeys) {
                        Date expireAt = apiKey.getExpireAt();
                        if (!apiKey.isRevoked() && (expireAt == null || expireAt.equals(now) || expireAt.before(now))) {
                            apiKey.setExpireAt(endingAt);
                            apiKey.setRevokedAt(endingAt);
                            apiKey.setRevoked(true);
                            apiKeyService.update(apiKey);
                        }
                    }
                }

                return convert(subscription);
            }

            throw new SubscriptionNotClosableException(subscriptionId);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to close subscription {}", subscriptionId, ex);
            throw new TechnicalManagementException(String.format(
                    "An error occurs while trying to close subscription %s", subscriptionId), ex);
        }
    }

    @Override
    public void delete(String subscriptionId) {
        try {
            LOGGER.debug("Delete subscription {}", subscriptionId);

            Optional optSubscription = subscriptionRepository.findById(subscriptionId);
            if (! optSubscription.isPresent()) {
                throw new SubscriptionNotFoundException(subscriptionId);
            }

            // Delete API Keys
            apiKeyService.findBySubscription(subscriptionId)
                    .forEach(apiKey -> apiKeyService.delete(apiKey.getKey()));

            // Delete subscription
            subscriptionRepository.delete(subscriptionId);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to delete subscription: {}", subscriptionId, ex);
            throw new TechnicalManagementException(
                    String.format("An error occurs while trying to delete subscription: %s", subscriptionId), ex);
        }
    }

    private SubscriptionEntity convert(Subscription subscription) {
        SubscriptionEntity entity = new SubscriptionEntity();

        entity.setId(subscription.getId());
        entity.setPlan(subscription.getPlan());
        entity.setProcessedAt(subscription.getProcessedAt());
        entity.setStatus(SubscriptionStatus.valueOf(subscription.getStatus().name()));
        entity.setProcessedBy(subscription.getProcessedBy());
        entity.setReason(subscription.getReason());
        entity.setApplication(subscription.getApplication());
        entity.setStartingAt(subscription.getStartingAt());
        entity.setEndingAt(subscription.getEndingAt());
        entity.setCreatedAt(subscription.getCreatedAt());
        entity.setUpdatedAt(subscription.getUpdatedAt());
        entity.setSubscribedBy(subscription.getSubscribedBy());

        return entity;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy