content: /*
   * 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.ambari.server.audit.request.eventcreator;
  
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.SortedMap;
  import java.util.TreeMap;
  
  import org.apache.ambari.server.api.services.Request;
  import org.apache.ambari.server.api.services.Result;
  import org.apache.ambari.server.api.services.ResultStatus;
  import org.apache.ambari.server.audit.event.AuditEvent;
  import org.apache.ambari.server.audit.event.request.AddRepositoryVersionRequestAuditEvent;
  import org.apache.ambari.server.audit.event.request.ChangeRepositoryVersionRequestAuditEvent;
  import org.apache.ambari.server.audit.event.request.DeleteRepositoryVersionRequestAuditEvent;
  import org.apache.ambari.server.controller.internal.OperatingSystemResourceProvider;
  import org.apache.ambari.server.controller.internal.RepositoryResourceProvider;
  import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
  import org.apache.ambari.server.controller.spi.Resource;
  
  import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Iterables;
  
  /**
   * This creator handles privilege requests
   * For resource type {@link Resource.Type#Repository}
   * and request types {@link Request.Type#POST}, {@link Request.Type#PUT} and {@link Request.Type#DELETE}
   */
  public class RepositoryVersionEventCreator implements RequestAuditEventCreator {
  
    /**
     * Set of {@link Request.Type}s that are handled by this plugin
     */
    private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
  
    /**
     * Set of {@link Resource.Type}s that are handled by this plugin
     */
    private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.RepositoryVersion).build();
  
    /**
     * {@inheritDoc}
     */
    @Override
    public Set<Request.Type> getRequestTypes() {
      return requestTypes;
    }
  
    /**
     * {@inheritDoc}
     */
    @Override
    public Set<Resource.Type> getResourceTypes() {
      return resourceTypes;
    }
  
    /**
     * {@inheritDoc}
     */
    @Override
    public Set<ResultStatus.STATUS> getResultStatuses() {
      return null;
    }
  
    /**
     * {@inheritDoc}
     */
    @Override
    public AuditEvent createAuditEvent(Request request, Result result) {
  
      switch (request.getRequestType()) {
        case POST:
          return AddRepositoryVersionRequestAuditEvent.builder()
            .withTimestamp(System.currentTimeMillis())
            .withRequestType(request.getRequestType())
            .withResultStatus(result.getStatus())
            .withUrl(request.getURI())
            .withRemoteIp(request.getRemoteAddress())
            .withStackName(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID))
            .withStackVersion(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID))
            .withDisplayName(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID))
            .withRepoVersion(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID))
            .withRepos(getRepos(request))
            .build();
        case PUT:
          return ChangeRepositoryVersionRequestAuditEvent.builder()
            .withTimestamp(System.currentTimeMillis())
            .withRequestType(request.getRequestType())
            .withResultStatus(result.getStatus())
            .withUrl(request.getURI())
            .withRemoteIp(request.getRemoteAddress())
            .withStackName(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID))
            .withStackVersion(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID))
            .withDisplayName(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID))
            .withRepoVersion(RequestAuditEventCreatorHelper.getProperty(request, RepositoryVersionResourceProvider.REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID))
            .withRepos(getRepos(request))
            .build();
        case DELETE:
          return DeleteRepositoryVersionRequestAuditEvent.builder()
            .withTimestamp(System.currentTimeMillis())
            .withRequestType(request.getRequestType())
            .withResultStatus(result.getStatus())
            .withUrl(request.getURI())
            .withRemoteIp(request.getRemoteAddress())
            .withStackName(request.getResource().getKeyValueMap().get(Resource.Type.Stack))
            .withStackVersion(request.getResource().getKeyValueMap().get(Resource.Type.StackVersion))
            .withRepoVersion(request.getResource().getKeyValueMap().get(Resource.Type.RepositoryVersion))
            .build();
        default:
          return null;
      }
    }
  
    /**
     * Assembles repositories from the request
     * operating system -> list of repositories where the repository is a map of properties (repo_id, repo_name, base_url)
     * @param request
     * @return a map of repositories
     */
    private SortedMap<String, List<Map<String, String>>> getRepos(Request request) {
  
      SortedMap<String, List<Map<String, String>>> result = new TreeMap<>();
  
      Map<String, Object> first = Iterables.getFirst(request.getBody().getPropertySets(), null);
  
      if (first != null && first.get("operating_systems") instanceof Set) {
        Set<?> set = (Set<?>) first.get("operating_systems");
        result = createResultForOperationSystems(set);
      }
      return result;
    }
  
    /**
     * Returns repos for the set of operating systems
     * @param set
     * @return
     */
    private SortedMap<String, List<Map<String, String>>> createResultForOperationSystems(Set<?> set) {
      SortedMap<String, List<Map<String, String>>> result = new TreeMap<>();
      for (Object entry : set) {
        if (entry instanceof Map) {
          Map<?, ?> map = (Map<?, ?>) entry;
          String osType = (String) map.get(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
          if (!result.containsKey(osType)) {
            result.put(osType, new LinkedList<>());
          }
          if (map.get("repositories") instanceof Set) {
            Set<?> repos = (Set<?>) map.get("repositories");
            for (Object repo : repos) {
              if (repo instanceof Map) {
                Map<String, String> resultMap = buildResultRepo((Map<String, String>) repo);
                result.get(osType).add(resultMap);
              }
            }
          }
        }
      }
      return result;
    }
  
    /**
     * Returns a map with the repository properties (repo_id, repo_name, base_url)
     * @param repo
     * @return
     */
    private Map<String, String> buildResultRepo(Map<String, String> repo) {
      Map<String, String> m = repo;
      String repoId = m.get(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID);
      String repo_name = m.get(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID);
      String baseUrl = m.get(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID);
      Map<String, String> resultMap = new HashMap<>();
      resultMap.put("repo_id", repoId);
      resultMap.put("repo_name", repo_name);
      resultMap.put("base_url", baseUrl);
      return resultMap;
    }
  }
  