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.view.utils.ambari;
  
  import org.apache.ambari.view.AmbariHttpException;
  import org.apache.ambari.view.URLStreamProvider;
  import org.apache.ambari.view.ViewContext;
  import org.apache.ambari.view.cluster.Cluster;
  import org.apache.commons.io.IOUtils;
  import org.json.simple.JSONArray;
  import org.json.simple.JSONObject;
  import org.json.simple.JSONValue;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  /**
   * Provides API to Ambari. Supports both Local and Remote cluster association.
   * Also provides API to get cluster topology (determine what node contains specific service)
   * on both local and remote cluster.
   */
  public class AmbariApi {
  
    private ViewContext context;
    private Services services;
  
    private String requestedBy = "views";
  
    public static String API_PREFIX = "/api/v1/clusters/";
  
    /**
     * Constructor for Ambari API based on ViewContext
     * @param context View Context
     */
    public AmbariApi(ViewContext context) {
      this.context = context;
    }
  
    /**
     *  Set requestedBy header
     *
     * @param requestedBy
     */
    public void setRequestedBy(String requestedBy) {
      this.requestedBy = requestedBy;
    }
  
    /**
     * Shortcut for GET method
     * @param path REST API path
     * @return response
     * @throws AmbariApiException
     */
    public String requestClusterAPI(String path) throws AmbariApiException, AmbariHttpException {
      return requestClusterAPI(path, "GET", null, null);
    }
  
    /**
     * Request to Ambari REST API for current cluster. Supports both local and remote cluster
     * @param path REST API path after cluster name e.g. /api/v1/clusters/mycluster/[method]
     * @param method HTTP method
     * @param data HTTP data
     * @param headers HTTP headers
     * @return response
     * @throws AmbariApiException IO error or not associated with cluster
     */
    public String requestClusterAPI(String path, String method, String data, Map<String, String> headers) throws AmbariApiException, AmbariHttpException {
      String response;
  
      try {
  
        if (context.getAmbariClusterStreamProvider() == null || context.getCluster() == null) {
          throw new NoClusterAssociatedException(
              "RA030 View is not associated with any cluster. No way to request Ambari.");
        }
  
        if(!path.startsWith("/")) path = "/" + path;
  
        path =  API_PREFIX + context.getCluster().getName() + path;
  
        InputStream inputStream = context.getAmbariClusterStreamProvider().readFrom(path, method, data, addRequestedByHeader(headers));
        response = IOUtils.toString(inputStream);
      } catch (IOException e) {
        throw new AmbariApiException("RA040 I/O error while requesting Ambari", e);
      }
      return response;
    }
  
    /**
     * Request to Ambari REST API. Supports both local and remote cluster
     * @param path REST API path, e.g. /api/v1/clusters/mycluster/
     * @param method HTTP method
     * @param data HTTP data
     * @param headers HTTP headers
     * @return response
     * @throws AmbariApiException IO error or not associated with cluster
     */
    public String readFromAmbari(String path, String method, String data, Map<String, String> headers) throws AmbariApiException, AmbariHttpException {
      String response;
  
      try {
  
        if (context.getAmbariClusterStreamProvider() == null) {
          throw new NoClusterAssociatedException(
              "RA060 View is not associated with any cluster. No way to request Ambari.");
        }
  
        InputStream inputStream = context.getAmbariClusterStreamProvider().readFrom(path, method, data, addRequestedByHeader(headers));
        response = IOUtils.toString(inputStream);
      } catch (IOException e) {
        throw new AmbariApiException("RA050 I/O error while requesting Ambari", e);
      }
  
      return response;
    }
  
  
  
    /**
     * Provides access to service-specific utilities
     * @return object with service-specific methods
     */
    public Services getServices() {
      if (services == null) {
        services = new Services(this, context);
      }
      return services;
    }
  
    private Map<String,String> addRequestedByHeader(Map<String,String> headers){
      if(headers == null){
        headers = new HashMap<String, String>();
      }
  
      headers.put("X-Requested-By",this.requestedBy);
  
      return headers;
    }
  
    /**
     * Check if view is associated with cluster
     *
     * @return isClusterAssociated
     */
    public boolean isClusterAssociated(){
      return context.getCluster() != null;
    }
  
  }
  