Package com.cloud.stack

Source Code of com.cloud.stack.CloudStackClient

/*
* Copyright (C) 2011 Citrix Systems, Inc.  All rights reserved.
*
* 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 com.cloud.stack;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import org.apache.log4j.Logger;

import com.cloud.bridge.util.JsonAccessor;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

/**
* CloudStackClient implements a simple CloudStack client object, it can be used to execute CloudStack commands
* with JSON response
*
* @author Kelven Yang
*/
public class CloudStackClient {
    protected final static Logger logger = Logger.getLogger(CloudStackClient.class);
   
  private String _serviceUrl;
 
  private long _pollIntervalMs = 2000;      // 1 second polling interval
  private long _pollTimeoutMs = 600000;      // 10 minutes polling timeout

  public CloudStackClient(String serviceRootUrl) {
    assert(serviceRootUrl != null);
   
    if(!serviceRootUrl.endsWith("/"))
      _serviceUrl = serviceRootUrl + "/api?";
    else
      _serviceUrl = serviceRootUrl + "api?";
  }
 
  public CloudStackClient(String cloudStackServiceHost, int port, boolean bSslEnabled) {
    StringBuffer sb = new StringBuffer();
    if(!bSslEnabled) {
      sb.append("http://" + cloudStackServiceHost);
      if(port != 80)
        sb.append(":").append(port);
    } else {
      sb.append("https://" + cloudStackServiceHost);
      if(port != 443)
        sb.append(":").append(port);
    }
   
    //
    // If the CloudStack root context path has been from /client to some other name
    // use the first constructor instead
    //
    sb.append("/client/api");
    sb.append("?");
    _serviceUrl = sb.toString();
  }
 
  public CloudStackClient setPollInterval(long intervalMs) {
    _pollIntervalMs = intervalMs;
    return this;
  }
 
  public CloudStackClient setPollTimeout(long pollTimeoutMs) {
    _pollTimeoutMs = pollTimeoutMs;
    return this;
  }
 
  public <T> T call(CloudStackCommand cmd, String apiKey, String secretKey, boolean followToAsyncResult,
    String responseName, String responseObjName, Class<T> responseClzthrows Exception {
   
    assert(responseName != null);
   
    JsonAccessor json = execute(cmd, apiKey, secretKey);
    if(followToAsyncResult && json.tryEval(responseName + ".jobid") != null) {
      long startMs = System.currentTimeMillis();
          while(System.currentTimeMillis() -  startMs < _pollTimeoutMs) {
        CloudStackCommand queryJobCmd = new CloudStackCommand("queryAsyncJobResult");
            queryJobCmd.setParam("jobId", json.getAsString(responseName + ".jobid"));
           
            JsonAccessor queryAsyncJobResponse = execute(queryJobCmd, apiKey, secretKey);

          if(queryAsyncJobResponse.tryEval("queryasyncjobresultresponse") != null) {
            int jobStatus = queryAsyncJobResponse.getAsInt("queryasyncjobresultresponse.jobstatus");
            switch(jobStatus) {
            case 2:
                throw new Exception(queryAsyncJobResponse.getAsString("queryasyncjobresultresponse.jobresult.errorcode") + " " +
                  queryAsyncJobResponse.getAsString("queryasyncjobresultresponse.jobresult.errortext"));
               
            case 0 :
                    try {
                      Thread.sleep( _pollIntervalMs );
                    } catch( Exception e ) {}
                    break;
                   
            case 1 :
              if(responseObjName != null)
                return (T)(new Gson()).fromJson(queryAsyncJobResponse.eval("queryasyncjobresultresponse.jobresult." + responseObjName), responseClz);
              else
                return (T)(new Gson()).fromJson(queryAsyncJobResponse.eval("queryasyncjobresultresponse.jobresult"), responseClz);
             
            default :
              assert(false);
                      throw new Exception("Operation failed - invalid job status response");
            }
          } else {
                  throw new Exception("Operation failed - invalid JSON response");
          }
          }
         
            throw new Exception("Operation failed - async-job query timed out");
    } else {
      if (responseObjName != null)
        return (T)(new Gson()).fromJson(json.eval(responseName + "." + responseObjName), responseClz);
      else
        return (T)(new Gson()).fromJson(json.eval(responseName), responseClz);
    }
  }

  // collectionType example :  new TypeToken<List<String>>() {}.getType();
  public <T> List<T> listCall(CloudStackCommand cmd, String apiKey, String secretKey,
    String responseName, String responseObjName, Type collectionType) throws Exception {
   
    assert(responseName != null);
   
    JsonAccessor json = execute(cmd, apiKey, secretKey);
   
   

    if(responseObjName != null)
      try {
        return (new Gson()).fromJson(json.eval(responseName + "." + responseObjName), collectionType);
      } catch(Exception e) {
        // this happens because responseObjName won't exist if there are no objects in the list.
        logger.debug("Unable to find responseObjName:[" + responseObjName + "].  Returning null! Exception: " + e.getMessage());
        return null;
      }
    return (new Gson()).fromJson(json.eval(responseName), collectionType);
  }

  public JsonAccessor execute(CloudStackCommand cmd, String apiKey, String secretKey) throws Exception {
    JsonParser parser = new JsonParser();
    URL url = new URL(_serviceUrl + cmd.signCommand(apiKey, secretKey));
   
    if(logger.isDebugEnabled())
      logger.debug("Cloud API call + [" + url.toString() + "]");
   
        URLConnection connect = url.openConnection();
       
        int statusCode;
        statusCode = ((HttpURLConnection)connect).getResponseCode();
        if(statusCode >= 400) {
      logger.error("Cloud API call + [" + url.toString() + "] failed with status code: " + statusCode);
            String errorMessage = ((HttpURLConnection)connect).getResponseMessage();
            if(errorMessage == null){
                errorMessage = connect.getHeaderField("X-Description");
            }
           
            if(errorMessage == null){
                errorMessage = "CloudStack API call HTTP response error, HTTP status code: " + statusCode;
            }
     
      throw new IOException(errorMessage);
        }

       
        InputStream inputStream = connect.getInputStream();
    JsonElement jsonElement = parser.parse(new InputStreamReader(inputStream));
    if(jsonElement == null) {
          logger.error("Cloud API call + [" + url.toString() + "] failed: unable to parse expected JSON response");
         
          throw new IOException("CloudStack API call error : invalid JSON response");
    }
   
    if(logger.isDebugEnabled())
      logger.debug("Cloud API call + [" + url.toString() + "] returned: " + jsonElement.toString());
    return new JsonAccessor(jsonElement);
  }
}
TOP

Related Classes of com.cloud.stack.CloudStackClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.