/** * 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) [2010], 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.rabbitmq.core; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.net.URLEncoder; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Properties; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.auth.AuthScope; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.AuthCache; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.ClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.protocol.BasicHttpContext; import org.hyperic.hq.agent.AgentKeystoreConfig; import org.hyperic.hq.product.PluginException; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.http.HQHttpClient; import org.hyperic.util.http.HttpConfig; /** * A HypericRabbitAdmin is created for each node/virtualHost. * HypericRabbitAdmin * @author Helena Edelson */ public final class HypericRabbitAdmin { private static final Log logger = LogFactory.getLog(HypericRabbitAdmin.class); private final DefaultHttpClient client; private String user; private String pass; private BasicHttpContext localcontext; private HttpHost targetHost; public HypericRabbitAdmin(Properties props) throws PluginException { int port = Integer.parseInt(props.getProperty(DetectorConstants.PORT)); String addr = props.getProperty(DetectorConstants.ADDR); boolean https = "true".equals(props.getProperty(DetectorConstants.HTTPS)); this.user = props.getProperty(DetectorConstants.USERNAME); this.pass = props.getProperty(DetectorConstants.PASSWORD); targetHost = new HttpHost(addr, port, https ? "https" : "http"); AgentKeystoreConfig config = new AgentKeystoreConfig(); client = new HQHttpClient(config, new HttpConfig(5000, 5000, null, 0), config.isAcceptUnverifiedCert()); client.getCredentialsProvider().setCredentials( new AuthScope(targetHost.getHostName(), targetHost.getPort(), "Management: Web UI"), new UsernamePasswordCredentials(user, pass)); List authPrefs = new ArrayList(1); authPrefs.add("Management: Web UI"); AuthCache authCache = new BasicAuthCache(); BasicScheme basicAuth = new BasicScheme(); authCache.put(targetHost, basicAuth); localcontext = new BasicHttpContext(); localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache); } public HypericRabbitAdmin(ConfigResponse props) throws PluginException { this(props.toProperties()); } public RabbitOverview getOverview() throws PluginException { return get("/api/overview", RabbitOverview.class); } public List<RabbitVirtualHost> getVirtualHosts() throws PluginException { List<RabbitVirtualHost> res; try { res = Arrays.asList(get("/api/vhosts", RabbitVirtualHost[].class)); } catch (PluginException ex) { logger.debug("[getVirtualHosts] " + ex.getLocalizedMessage(),ex); res = new ArrayList<RabbitVirtualHost>(); List<String> names = Arrays.asList(get("/api/vhosts", String[].class)); for (String name : names) { res.add(new RabbitVirtualHost(name)); } } return res; } public List<RabbitQueue> getQueues(RabbitVirtualHost vh) throws PluginException { try { return Arrays.asList(get("/api/queues/" + URLEncoder.encode(vh.getName(), "UTF-8"), RabbitQueue[].class)); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } } public List<RabbitExchange> getExchanges(RabbitVirtualHost vh) throws PluginException { try { return Arrays.asList(get("/api/exchanges/" + URLEncoder.encode(vh.getName(), "UTF-8"), RabbitExchange[].class)); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } } public List<RabbitConnection> getConnections() throws PluginException { return Arrays.asList(get("/api/connections", RabbitConnection[].class)); } public RabbitConnection getConnection(String cName) throws PluginException { try { cName = URLEncoder.encode(cName, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } return get("/api/connections/" + cName, RabbitConnection.class); } public List<RabbitChannel> getChannels() throws PluginException { return Arrays.asList(get("/api/channels", RabbitChannel[].class)); } public RabbitChannel getChannel(String chName) throws PluginException { try { chName = URLEncoder.encode(chName, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } return get("/api/channels/" + chName, RabbitChannel.class); } public RabbitVirtualHost getVirtualHost(String vhName) throws PluginException { try { vhName = URLEncoder.encode(vhName, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } RabbitVirtualHost res; try { res = get("/api/vhosts/" + vhName, RabbitVirtualHost.class); } catch (PluginException ex) { logger.debug("[getVirtualHost] " + ex.getLocalizedMessage(),ex); String name = get("/api/vhosts/" + vhName, String.class); res = new RabbitVirtualHost(name); } return res; } public RabbitQueue getVirtualQueue(String vhName, String qName) throws PluginException { try { vhName = URLEncoder.encode(vhName, "UTF-8"); qName = URLEncoder.encode(qName, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } return get("/api/queues/" + vhName + "/" + qName, RabbitQueue.class); } public RabbitExchange getExchange(String vhost, String exch) throws PluginException { try { vhost = URLEncoder.encode(vhost, "UTF-8"); exch = URLEncoder.encode(exch, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } return get("/api/exchanges/" + vhost + "/" + exch, RabbitExchange.class); } public RabbitNode getNode(String node) throws PluginException { RabbitNode res; try { node = URLEncoder.encode(node, "UTF-8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } try { res = get("/api/nodes/" + node, RabbitNode.class); } catch (PluginException ex) { logger.debug("[getVirtualHost] " + ex.getLocalizedMessage(),ex); res = get("/api/overview/", RabbitNode.class); res.setName(node); res.setRunning(true); } return res; } private <T extends Object> T get(String api, Class<T> classOfT) throws PluginException { T res = null; try { HttpGet get = new HttpGet(targetHost.toURI() + api); HttpResponse response = client.execute(get, localcontext); int r = response.getStatusLine().getStatusCode(); // response must be read in order to "close" the connection. // https://jira.hyperic.com/browse/HHQ-5063#comment-154101 String responseBody = readInputString(response.getEntity().getContent()); if (logger.isDebugEnabled()) { logger.debug("[" + api + "] -(" + r + ")-> " + responseBody); } if (r != 200) { throw new PluginException("[" + api + "] http error code: '" + r + "'"); } GsonBuilder gsb = new GsonBuilder(); gsb.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); gsb.registerTypeAdapter(Integer.class, new IntegerDeserializer()); gsb.registerTypeAdapter(int.class, new IntegerDeserializer()); gsb.registerTypeAdapter(Date.class, new DateTimeDeserializer()); gsb.registerTypeAdapter(MessageStats.class, new MessageStatsDeserializer()); Gson gson = gsb.create(); res = gson.fromJson(responseBody, classOfT); if (logger.isDebugEnabled()) { if (res.getClass().isArray()) { logger.debug("[" + api + "] -(" + r + ")*> " + Arrays.asList((Object[]) res)); } else { logger.debug("[" + api + "] -(" + r + ")-> " + res); } } } catch (IOException ex) { logger.debug(ex.getMessage(), ex); throw new PluginException(ex.getMessage(), ex); } return res; } private class DateTimeDeserializer implements JsonDeserializer<Date> { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { return (Date) formatter.parse(json.getAsString()); } catch (ParseException ex) { throw new JsonParseException(ex.getMessage(), ex); } } } private class IntegerDeserializer implements JsonDeserializer<Integer> { public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { try { return json.getAsInt(); } catch (NumberFormatException ex) { if (json.getAsString().equals("install_handle_from_sysinternals")) { logger.debug("'Handle V3.42 (sysinternals)' is required by 'rabbitmq-management-agent' plugin on Windows Platforms. " + ex.getMessage()); return null; } throw new JsonParseException(ex.getMessage(), ex); } } } private class MessageStatsDeserializer implements JsonDeserializer<MessageStats> { public MessageStats deserialize(JsonElement je, Type Type, JsonDeserializationContext jdc) throws JsonParseException { MessageStats res = null; if (je.isJsonArray()) { res = new MessageStats(); } else { GsonBuilder gsb = new GsonBuilder(); gsb.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); Gson gson = gsb.create(); res = gson.fromJson(je, Type); } return res; } } public static String readInputString(InputStream in) throws IOException { StringBuilder out = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = in.read(b)) != -1;) { out.append(new String(b, 0, n)); } return out.toString(); } }