/*
* NOTE: This copyright does *not* cover user programs that use Hyperic
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004-2011], VMware, Inc.
* This file is part of Hyperic.
*
* Hyperic is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.hq.plugin.cloudfoundry.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.client.lib.ApplicationStats;
import org.cloudfoundry.client.lib.CloudApplication;
import org.cloudfoundry.client.lib.CloudFoundryClient;
import org.cloudfoundry.client.lib.CloudInfo;
import org.cloudfoundry.client.lib.CloudService;
import org.cloudfoundry.client.lib.CrashesInfo;
import org.hyperic.hq.product.PluginException;
import org.json.JSONException;
import org.json.JSONObject;
public class CloudFoundryProxy {
private static final Log _log = LogFactory.getLog(CloudFoundryProxy.class);
private static final long CACHE_TIMEOUT = 60000;
// TODO: Move to constants file
private static final String EMAIL = "email";
private static final String PASSWORD = "password";
private static final String URI = "uri";
private static Map<String, String> tokenCache = new HashMap<String, String>();
private Properties config = null;
private CloudFoundryClient cf = null;
public CloudFoundryProxy(Properties config) throws PluginException {
this.config = config;
this.cf = getCloudFoundryClient(this.config);
}
public CloudInfo getCloudInfo() {
CloudInfo info = null;
try {
info = this.cf.getCloudInfo();
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting cloud info. Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
info = this.cf.getCloudInfo();
} catch (PluginException e2) {
_log.error("Error getting cloud info", e2);
}
}
return info;
}
public List<CloudApplication> getApplications() {
List<CloudApplication> apps = null;
try {
apps = this.cf.getApplications();
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting apps. Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
apps = this.cf.getApplications();
} catch (PluginException e2) {
_log.error("Error getting services", e2);
}
}
return apps;
}
public CloudApplication getApplication(String appName) {
CloudApplication app = null;
try {
app = this.cf.getApplication(appName);
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting app " + appName
+ ". Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
app = this.cf.getApplication(appName);
} catch (PluginException e2) {
_log.error("Error getting app " + appName, e2);
}
}
return app;
}
public ApplicationStats getApplicationStats(String appName) {
ApplicationStats stats = null;
try {
stats = this.cf.getApplicationStats(appName);
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting app stats for "
+ appName + ". Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
stats = this.cf.getApplicationStats(appName);
} catch (PluginException e2) {
_log.error("Error getting app stats for "
+ appName, e2);
}
}
return stats;
}
public List<CloudService> getServices() {
List<CloudService> services = null;
try {
services = this.cf.getServices();
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting services. Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
services = this.cf.getServices();
} catch (PluginException e2) {
_log.error("Error getting services", e2);
}
}
return services;
}
public CloudService getService(String serviceName) {
CloudService service = null;
try {
service = this.cf.getService(serviceName);
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting service "
+ serviceName + ". Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
service = this.cf.getService(serviceName);
} catch (PluginException e2) {
_log.error("Error getting service " + serviceName, e2);
}
}
return service;
}
public CrashesInfo getCrashes(String appName) {
CrashesInfo info = null;
try {
info = this.cf.getCrashes(appName);
} catch (Exception e1) {
if (_log.isDebugEnabled()) {
_log.debug("Error getting app crashes for "
+ appName + ". Re-trying with new client.", e1);
}
try {
this.cf = getNewCloudFoundryClient(this.config);
info = this.cf.getCrashes(appName);
} catch (PluginException e2) {
_log.error("Error getting app crashes for "
+ appName, e2);
}
}
return info;
}
private CloudFoundryClient getCloudFoundryClient(Properties config)
throws PluginException {
CloudFoundryClient cf = null;
JSONObject key = getJSONKey(config);
synchronized (tokenCache) {
String token = tokenCache.get(key.toString());
if (token == null) {
cf = getNewCloudFoundryClient(config);
} else {
try {
String uri = key.getString(URI);
// generate new client with the cached token
// to ensure data is fresh
cf = new CloudFoundryClient(token, uri);
if (_log.isDebugEnabled()) {
_log.debug("Using cached token = " + token);
}
} catch (Exception e) {
throw new PluginException("Error creating CloudFoundryClient", e);
}
}
}
return cf;
}
private CloudFoundryClient getNewCloudFoundryClient(Properties config)
throws PluginException {
CloudFoundryClient cf = null;
synchronized (tokenCache) {
JSONObject key = getJSONKey(config);
tokenCache.remove(key);
cf = CloudFoundryFactory.getCloudFoundryClient(config);
String token = null;
try {
token = cf.login();
} catch (Exception ex) {
_log.info(ex.getMessage());
throw new PluginException("Invalid Cloud Foundry credentials", ex);
}
tokenCache.put(key.toString(), token);
if (_log.isDebugEnabled()) {
_log.debug("key=" + key + ", new token=" + token);
}
}
return cf;
}
/*
private CloudAccount getCloudAccount(Properties config)
throws PluginException {
CloudFoundryClient cf = getCloudFoundryClient(config);
CloudInfo info = null;
try {
info = cf.getCloudInfo();
} catch (Exception e) {
_log.info("Error getting cloud info. Re-trying with new client.", e);
cf = getNewCloudFoundryClient(config);
info = cf.getCloudInfo();
}
CloudAccount cloud = new CloudAccount(info);
List<CloudApplication> apps = cf.getApplications();
for (CloudApplication app : apps) {
String appName = app.getName();
ApplicationStats stats = cf.getApplicationStats(appName);
cloud.addApplication(app);
cloud.addApplicationStats(appName, stats);
}
List<CloudService> services = cf.getServices();
for (CloudService s : services) {
cloud.addService(s);
}
return cloud;
}
*/
private JSONObject getJSONKey(Properties config) {
JSONObject jsonKey = null;
String email = config.getProperty(EMAIL);
String cloudControllerUrl = config.getProperty(URI);
if (email.length() > 0
&& cloudControllerUrl.length() > 0) {
try {
jsonKey = new JSONObject();
jsonKey.put(EMAIL, email);
jsonKey.put(URI, cloudControllerUrl);
} catch (JSONException je) {
throw new IllegalArgumentException(je);
}
} else {
throw new IllegalArgumentException("Missing Cloud Foundry credentials");
}
return jsonKey;
}
}