content: package alien4cloud.rest.deployment;
  
  import java.security.Principal;
  import java.util.Date;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import javax.annotation.Resource;
  
  import lombok.extern.slf4j.Slf4j;
  
  import org.elasticsearch.mapping.MappingBuilder;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.messaging.simp.SimpMessagingTemplate;
  import org.springframework.security.core.Authentication;
  import org.springframework.stereotype.Component;
  
  import alien4cloud.dao.IGenericSearchDAO;
  import alien4cloud.exception.NotFoundException;
  import alien4cloud.model.application.ApplicationEnvironment;
  import alien4cloud.model.deployment.Deployment;
  import alien4cloud.paas.IPaasEventListener;
  import alien4cloud.paas.IPaasEventService;
  import alien4cloud.paas.model.AbstractMonitorEvent;
  import alien4cloud.paas.model.AbstractPaaSWorkflowMonitorEvent;
  import alien4cloud.paas.model.DeploymentStatus;
  import alien4cloud.paas.model.PaaSDeploymentStatusMonitorEvent;
  import alien4cloud.rest.websocket.ISecuredHandler;
  import alien4cloud.security.AuthorizationUtil;
  import alien4cloud.security.model.ApplicationEnvironmentRole;
  import alien4cloud.security.model.ApplicationRole;
  import alien4cloud.security.model.Role;
  import alien4cloud.security.model.User;
  
  @Slf4j
  @Component
  public class DeploymentEventHandler implements IPaasEventListener<AbstractMonitorEvent>, ISecuredHandler, InitializingBean {
  
      private static final String TOPIC_PREFIX = "/topic/deployment-events";
      private static final String ENV_TOPIC_PREFIX = "/topic/environment-events";
  
      private static final Pattern DESTINATION_PATTERN = Pattern.compile(TOPIC_PREFIX + "/(.*?)(:?/.*)?");
      private static final Pattern ENV_DESTINATION_PATTERN = Pattern.compile(ENV_TOPIC_PREFIX + "/(.*?)(:?/.*)?");
  
      @Resource
      private IPaasEventService paasEventService;
  
      @Resource(name = "alien-es-dao")
      private IGenericSearchDAO alienDAO;
  
      @Resource
      private SimpMessagingTemplate template;
  
      protected void send(AbstractMonitorEvent event) {
          String eventType = MappingBuilder.indexTypeFromClass(event.getClass());
          String topicName = TOPIC_PREFIX + '/' + event.getDeploymentId() + '/' + eventType;
          dispatchEvent(event, topicName);
  
          if (event instanceof PaaSDeploymentStatusMonitorEvent) {
              Deployment deployment = alienDAO.findById(Deployment.class, event.getDeploymentId());
              if (deployment != null && deployment.getEnvironmentId() != null) {
                  // dispatch an event on the environment topic
                  topicName = ENV_TOPIC_PREFIX + "/" + deployment.getEnvironmentId();
                  dispatchEvent(event, topicName);
              }
          }
      }
  
      private void dispatchEvent(AbstractMonitorEvent event, String topicName) {
          log.debug("Send [{}] to [{}]: {}", event.getClass().getSimpleName(), topicName, event);
          template.convertAndSend(topicName, event);
      }
  
      /**
       * Check if the destination path can be handled by this event handler
       *
       * @param destination the destination
       * @return true if the event handler manage the destination
       */
      @Override
      public boolean canHandleDestination(String destination) {
          Matcher matcher = DESTINATION_PATTERN.matcher(destination);
          return matcher.matches();
      }
  
      /**
       * Check if the current user is authorized for this destination
       *
       * @param destination the destination
       */
      @Override
      public void checkAuthorization(Principal user, String destination) {
          Matcher matcher = DESTINATION_PATTERN.matcher(destination);
          Authentication authentication = (Authentication) user;
          User a4cUser = (User) authentication.getPrincipal();
          if (matcher.matches()) {
              String deploymentId = matcher.group(1);
              checkDeploymentAuthorization(authentication, a4cUser, deploymentId);
          } else {
              matcher = ENV_DESTINATION_PATTERN.matcher(destination);
              if (matcher.matches()) {
                  String environmentId = matcher.group(1);
                  checkEnvironmentAuthorization(a4cUser, environmentId);
              } else {
                  throw new IllegalArgumentException("Cannot handle this destination [" + destination + "]");
              }
          }
      }
  
      private void checkDeploymentAuthorization(Authentication authentication, User a4cUser, String deploymentId) {
          Deployment deployment = alienDAO.findById(Deployment.class, deploymentId);
          switch (deployment.getSourceType()) {
          case APPLICATION:
              // check if the user has right for the environment associated with the deployment.
              ApplicationEnvironment environment = alienDAO.findById(ApplicationEnvironment.class, deployment.getEnvironmentId());
              if (environment == null) {
                  log.error("Environment with id [{}] do not exist any more for deployment [{}]", deployment.getEnvironmentId(), deployment.getId());
                  throw new NotFoundException(
                          "Environment with id [" + deployment.getEnvironmentId() + "] do not exist any more for deployment [" + deployment.getId() + "]");
              }
              AuthorizationUtil.checkAuthorization(a4cUser, environment, ApplicationRole.APPLICATION_MANAGER, ApplicationEnvironmentRole.values());
              break;
          case CSAR:
              AuthorizationUtil.checkHasOneRoleIn(authentication, Role.COMPONENTS_MANAGER);
          }
      }
  
      private void checkEnvironmentAuthorization(User a4cUser, String environmentId) {
          ApplicationEnvironment environment = alienDAO.findById(ApplicationEnvironment.class, environmentId);
          if (environment == null) {
              log.error("Environment with id [{}] do not exist any more", environmentId);
              throw new NotFoundException("Environment with id [" + environmentId + "] do not exist any more");
          }
          AuthorizationUtil.checkAuthorization(a4cUser, environment, ApplicationRole.APPLICATION_MANAGER, ApplicationEnvironmentRole.values());
      }
  
      @Override
      public void eventHappened(AbstractMonitorEvent event) {
          send(event);
          if (log.isTraceEnabled()) {
              log.trace("Pushed event {} for deployment {}", event, event.getDeploymentId());
          }
      }
  
      @Override
      public boolean canHandle(AbstractMonitorEvent event) {
          return AbstractMonitorEvent.class.isAssignableFrom(event.getClass()) && !AbstractPaaSWorkflowMonitorEvent.class.isAssignableFrom(event.getClass());
      }
  
      @Override
      public void afterPropertiesSet() throws Exception {
          paasEventService.addListener(this);
      }
  }
  