Java tutorial
// 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 com.cloud.network.bigswitch; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.log4j.Logger; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; public class BigSwitchVnsApi { private static final Logger s_logger = Logger.getLogger(BigSwitchVnsApi.class); private final static String s_protocol = "http"; private final static String s_nsBaseUri = "/networkService/v1.1"; private final static String CONTENT_TYPE = "Content-Type"; private final static String ACCEPT = "Accept"; private final static String CONTENT_JSON = "application/json"; private final static String HTTP_HEADER_INSTANCE_ID = "INSTANCE_ID"; private final static String CLOUDSTACK_INSTANCE_ID = "org.apache.cloudstack"; private final static MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager(); private String _host; private HttpClient _client; /* This factory method is protected so we can extend this * in the unittests. */ protected HttpClient createHttpClient() { return new HttpClient(s_httpClientManager); } protected HttpMethod createMethod(String type, String uri, int port) throws BigSwitchVnsApiException { String url; try { url = new URL(s_protocol, _host, port, uri).toString(); } catch (MalformedURLException e) { s_logger.error("Unable to build BigSwitch API URL", e); throw new BigSwitchVnsApiException("Unable to build v API URL", e); } if ("post".equalsIgnoreCase(type)) { return new PostMethod(url); } else if ("get".equalsIgnoreCase(type)) { return new GetMethod(url); } else if ("delete".equalsIgnoreCase(type)) { return new DeleteMethod(url); } else if ("put".equalsIgnoreCase(type)) { return new PutMethod(url); } else { throw new BigSwitchVnsApiException("Requesting unknown method type"); } } public BigSwitchVnsApi() { _client = createHttpClient(); _client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); } public void setControllerAddress(String address) { this._host = address; } /** * Logs into the BigSwitch API. The cookie is stored in the <code>_authcookie<code> variable. * <p> * The method returns false if the login failed or the connection could not be made. * */ protected void login() throws BigSwitchVnsApiException { return; } public void createNetwork(NetworkData network) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + network.getNetwork().getTenantId() + "/networks"; executeCreateObject(network, new TypeToken<NetworkData>() { }.getType(), uri, Collections.<String, String>emptyMap()); } public void deleteNetwork(String tenantId, String networkId) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + tenantId + "/networks/" + networkId; executeDeleteObject(uri); } public void createPort(String networkUuid, PortData port) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + port.getPort().getTenantId() + "/networks/" + networkUuid + "/ports"; executeCreateObject(port, new TypeToken<PortData>() { }.getType(), uri, Collections.<String, String>emptyMap()); } public void modifyPort(String networkId, PortData port) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + port.getPort().getTenantId() + "/networks/" + networkId + "/ports"; executeUpdateObject(port, uri, Collections.<String, String>emptyMap()); } public void deletePort(String tenantId, String networkId, String portId) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + tenantId + "/networks/" + networkId + "/ports/" + portId; executeDeleteObject(uri); } public void modifyPortAttachment(String tenantId, String networkId, String portId, AttachmentData attachment) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + tenantId + "/networks/" + networkId + "/ports/" + portId + "/attachment"; executeUpdateObject(attachment, uri, Collections.<String, String>emptyMap()); } public void deletePortAttachment(String tenantId, String networkId, String portId) throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/tenants/" + tenantId + "/networks/" + networkId + "/ports/" + portId + "/attachment"; executeDeleteObject(uri); } public ControlClusterStatus getControlClusterStatus() throws BigSwitchVnsApiException { String uri = s_nsBaseUri + "/health"; ControlClusterStatus ccs = executeRetrieveObject(new TypeToken<ControlClusterStatus>() { }.getType(), uri, 80, null); ccs.setStatus(true); return ccs; } protected <T> void executeUpdateObject(T newObject, String uri, Map<String, String> parameters) throws BigSwitchVnsApiException { if (_host == null || _host.isEmpty()) { throw new BigSwitchVnsApiException("Hostname is null or empty"); } Gson gson = new Gson(); PutMethod pm = (PutMethod) createMethod("put", uri, 80); pm.setRequestHeader(CONTENT_TYPE, CONTENT_JSON); pm.setRequestHeader(ACCEPT, CONTENT_JSON); pm.setRequestHeader(HTTP_HEADER_INSTANCE_ID, CLOUDSTACK_INSTANCE_ID); try { pm.setRequestEntity(new StringRequestEntity(gson.toJson(newObject), CONTENT_JSON, null)); } catch (UnsupportedEncodingException e) { throw new BigSwitchVnsApiException("Failed to encode json request body", e); } executeMethod(pm); if (pm.getStatusCode() != HttpStatus.SC_OK) { String errorMessage = responseToErrorMessage(pm); pm.releaseConnection(); s_logger.error("Failed to update object : " + errorMessage); throw new BigSwitchVnsApiException("Failed to update object : " + errorMessage); } pm.releaseConnection(); } protected <T> void executeCreateObject(T newObject, Type returnObjectType, String uri, Map<String, String> parameters) throws BigSwitchVnsApiException { if (_host == null || _host.isEmpty()) { throw new BigSwitchVnsApiException("Hostname is null or empty"); } Gson gson = new Gson(); PostMethod pm = (PostMethod) createMethod("post", uri, 80); pm.setRequestHeader(CONTENT_TYPE, CONTENT_JSON); pm.setRequestHeader(ACCEPT, CONTENT_JSON); pm.setRequestHeader(HTTP_HEADER_INSTANCE_ID, CLOUDSTACK_INSTANCE_ID); try { pm.setRequestEntity(new StringRequestEntity(gson.toJson(newObject), CONTENT_JSON, null)); } catch (UnsupportedEncodingException e) { throw new BigSwitchVnsApiException("Failed to encode json request body", e); } executeMethod(pm); if (pm.getStatusCode() != HttpStatus.SC_OK) { String errorMessage = responseToErrorMessage(pm); pm.releaseConnection(); s_logger.error("Failed to create object : " + errorMessage); throw new BigSwitchVnsApiException("Failed to create object : " + errorMessage); } pm.releaseConnection(); return; } protected void executeDeleteObject(String uri) throws BigSwitchVnsApiException { if (_host == null || _host.isEmpty()) { throw new BigSwitchVnsApiException("Hostname is null or empty"); } DeleteMethod dm = (DeleteMethod) createMethod("delete", uri, 80); dm.setRequestHeader(CONTENT_TYPE, CONTENT_JSON); dm.setRequestHeader(ACCEPT, CONTENT_JSON); dm.setRequestHeader(HTTP_HEADER_INSTANCE_ID, CLOUDSTACK_INSTANCE_ID); executeMethod(dm); if (dm.getStatusCode() != HttpStatus.SC_OK) { String errorMessage = responseToErrorMessage(dm); dm.releaseConnection(); s_logger.error("Failed to delete object : " + errorMessage); throw new BigSwitchVnsApiException("Failed to delete object : " + errorMessage); } dm.releaseConnection(); } @SuppressWarnings("unchecked") protected <T> T executeRetrieveObject(Type returnObjectType, String uri, int port, Map<String, String> parameters) throws BigSwitchVnsApiException { if (_host == null || _host.isEmpty()) { throw new BigSwitchVnsApiException("Hostname is null or empty"); } GetMethod gm = (GetMethod) createMethod("get", uri, port); gm.setRequestHeader(CONTENT_TYPE, CONTENT_JSON); gm.setRequestHeader(ACCEPT, CONTENT_JSON); gm.setRequestHeader(HTTP_HEADER_INSTANCE_ID, CLOUDSTACK_INSTANCE_ID); if (parameters != null && !parameters.isEmpty()) { List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(parameters.size()); for (Entry<String, String> e : parameters.entrySet()) { nameValuePairs.add(new NameValuePair(e.getKey(), e.getValue())); } gm.setQueryString(nameValuePairs.toArray(new NameValuePair[0])); } executeMethod(gm); if (gm.getStatusCode() != HttpStatus.SC_OK) { String errorMessage = responseToErrorMessage(gm); gm.releaseConnection(); s_logger.error("Failed to retrieve object : " + errorMessage); throw new BigSwitchVnsApiException("Failed to retrieve object : " + errorMessage); } Gson gson = new Gson(); T returnValue; try { returnValue = (T) gson.fromJson(gm.getResponseBodyAsString(), returnObjectType); } catch (IOException e) { s_logger.error("IOException while retrieving response body", e); throw new BigSwitchVnsApiException(e); } finally { gm.releaseConnection(); } return returnValue; } protected void executeMethod(HttpMethodBase method) throws BigSwitchVnsApiException { try { _client.executeMethod(method); if (method.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { method.releaseConnection(); // login and try again login(); _client.executeMethod(method); } } catch (HttpException e) { s_logger.error("HttpException caught while trying to connect to the BigSwitch Controller", e); method.releaseConnection(); throw new BigSwitchVnsApiException("API call to BigSwitch Controller Failed", e); } catch (IOException e) { s_logger.error("IOException caught while trying to connect to the BigSwitch Controller", e); method.releaseConnection(); throw new BigSwitchVnsApiException("API call to BigSwitch Controller Failed", e); } } private String responseToErrorMessage(HttpMethodBase method) { assert method.isRequestSent() : "no use getting an error message unless the request is sent"; if ("text/html".equals(method.getResponseHeader(CONTENT_TYPE).getValue())) { // The error message is the response content // Safety margin of 1024 characters, anything longer is probably useless // and will clutter the logs try { return method.getResponseBodyAsString(1024); } catch (IOException e) { s_logger.debug("Error while loading response body", e); } } // The default return method.getStatusText(); } }