View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.monitor.integration;
20  
21  import static java.lang.Integer.parseInt;
22  import static java.lang.System.getProperty;
23  
24  import java.io.ByteArrayInputStream;
25  import java.io.ByteArrayOutputStream;
26  import java.io.IOException;
27  import java.net.Socket;
28  import java.net.URL;
29  import java.util.Collection;
30  import java.util.Map;
31  import java.util.Properties;
32  import java.util.Set;
33  
34  import javax.management.MBeanServerConnection;
35  import javax.management.MalformedObjectNameException;
36  import javax.management.ObjectName;
37  
38  import org.eclipse.jetty.client.ContentExchange;
39  import org.eclipse.jetty.client.HttpClient;
40  import org.eclipse.jetty.http.HttpMethods;
41  import org.eclipse.jetty.http.HttpStatus;
42  import org.eclipse.jetty.io.ByteArrayBuffer;
43  import org.eclipse.jetty.monitor.JMXMonitor;
44  import org.eclipse.jetty.monitor.jmx.EventNotifier;
45  import org.eclipse.jetty.monitor.jmx.EventState;
46  import org.eclipse.jetty.monitor.jmx.EventState.TriggerState;
47  import org.eclipse.jetty.monitor.jmx.EventTrigger;
48  import org.eclipse.jetty.monitor.jmx.MonitorAction;
49  import org.eclipse.jetty.monitor.triggers.AggregateEventTrigger;
50  import org.eclipse.jetty.util.log.Log;
51  import org.eclipse.jetty.util.log.Logger;
52  
53  
54  /* ------------------------------------------------------------ */
55  /**
56   */
57  public class JavaMonitorAction extends MonitorAction
58  {
59      private static final Logger LOG = Log.getLogger(JavaMonitorAction.class);
60  
61      private final HttpClient _client;
62      
63      private final String _url;
64      private final String _uuid;
65      private final String _appid;
66      
67      private String _srvip;
68      private String _session;
69      
70      /* ------------------------------------------------------------ */
71      /**
72       * @param notifier
73       * @param pollInterval
74       * @throws Exception 
75       * @throws MalformedObjectNameException 
76       */
77      public JavaMonitorAction(EventNotifier notifier, String url, String uuid, String appid, long pollInterval)
78          throws Exception
79      {
80          super(new AggregateEventTrigger(),notifier,pollInterval);
81          
82          _url = url;
83          _uuid = uuid;
84          _appid = appid;
85          
86          _client = new HttpClient();
87          _client.setTimeout(60000);
88          _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
89          
90          try
91          {
92              _client.start();
93              _srvip = getServerIP();
94          }
95          catch (Exception ex)
96          {
97              LOG.debug(ex);
98          }
99          
100         sendData(new Properties());
101      }
102 
103     /* ------------------------------------------------------------ */
104     /**
105      * @see org.eclipse.jetty.monitor.jmx.MonitorAction#execute(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
106      */
107     @Override
108     public void execute(EventTrigger trigger, EventState<?> state, long timestamp)
109     {
110         exec(trigger, state, timestamp);
111     }
112 
113     /* ------------------------------------------------------------ */
114     /**
115      * @param trigger
116      * @param state
117      * @param timestamp
118      */
119     private <T> void exec(EventTrigger trigger, EventState<T> state, long timestamp)
120     {
121         Collection<TriggerState<T>> trs = state.values();
122         
123         Properties data = new Properties();
124         for (TriggerState<T> ts :  trs)
125         {
126             Object value = ts.getValue();
127 
128             StringBuffer buffer = new StringBuffer();
129             buffer.append(value == null ? "" : value.toString());
130             buffer.append("|");
131             buffer.append(getClassID(value));
132             buffer.append("||");
133             buffer.append(ts.getDescription());
134             
135             data.setProperty(ts.getID(), buffer.toString());
136             
137             try
138             {
139                 sendData(data);
140             }
141             catch (Exception ex)
142             {
143                 LOG.debug(ex);
144             }
145         }
146      }
147     
148     /* ------------------------------------------------------------ */
149     /**
150      * @param data
151      * @throws Exception 
152      */
153     private void sendData(Properties data)
154         throws Exception
155     {
156         data.put("account", _uuid);
157         data.put("appserver", "Jetty");
158         data.put("localIp", _srvip);
159         if (_appid == null)
160             data.put("lowestPort", getHttpPort());
161         else
162             data.put("lowestPort", _appid);
163         if (_session != null)
164             data.put("session", _session);
165         
166         Properties response = sendRequest(data);
167         
168         parseResponse(response);
169     }
170 
171     /* ------------------------------------------------------------ */
172     /**
173      * @param request
174      * @return
175      * @throws Exception 
176      */
177     private Properties sendRequest(Properties request)
178         throws Exception
179     {
180         ByteArrayOutputStream reqStream = null;
181         ByteArrayInputStream resStream = null;
182         Properties response = null;
183     
184         try {
185             ContentExchange reqEx = new ContentExchange();
186             reqEx.setURL(_url);
187             reqEx.setMethod(HttpMethods.POST);
188             reqEx.addRequestHeader("Connection","close");
189             
190             reqStream = new ByteArrayOutputStream();
191             request.storeToXML(reqStream,null);
192             ByteArrayBuffer reqBuff = new ByteArrayBuffer(reqStream.toByteArray());
193 
194             reqEx.setRequestContent(reqBuff);
195             _client.send(reqEx);
196         
197             reqEx.waitForDone();
198             
199             if (reqEx.getResponseStatus() == HttpStatus.OK_200)
200             {
201                 response = new Properties();
202                 resStream = new ByteArrayInputStream(reqEx.getResponseContentBytes());
203                 response.loadFromXML(resStream);               
204             }
205         }
206         finally
207         {
208             try
209             {
210                 if (reqStream != null)
211                     reqStream.close();
212             }
213             catch (IOException ex)
214             {
215                 LOG.ignore(ex);
216             }
217             
218             try
219             {
220                 if (resStream != null)
221                     resStream.close();
222             }
223             catch (IOException ex)
224             {
225                 LOG.ignore(ex);
226             }
227         }
228         
229         return response;    
230     }
231     
232     /* ------------------------------------------------------------ */
233     private void parseResponse(Properties response)
234     {
235         if (response.get("onhold") != null)
236             throw new Error("Suspended");
237         
238 
239         if (response.get("session") != null)
240         {
241             _session = (String) response.remove("session");
242 
243             AggregateEventTrigger trigger = (AggregateEventTrigger)getTrigger();
244 
245             String queryString;
246             ObjectName[] queryResults;
247             for (Map.Entry<Object, Object> entry : response.entrySet())
248             {
249                 String[] values = ((String) entry.getValue()).split("\\|");
250 
251                 queryString = values[0];
252                 if (queryString.startsWith("com.javamonitor.openfire"))
253                     continue;
254                 
255                 if (queryString.startsWith("com.javamonitor"))
256                 {
257                     queryString = "org.eclipse.jetty.monitor.integration:type=javamonitortools,id=0";
258                 }
259                 
260                 queryResults = null;
261                 try
262                 {
263                     queryResults = queryNames(queryString);
264                 }
265                 catch (IOException e)
266                 {
267                     LOG.debug(e);
268                 }
269                 catch (MalformedObjectNameException e)
270                 {
271                     LOG.debug(e);
272                 }
273                 
274                 if (queryResults != null)
275                 {
276                     int idx = 0;
277                     for(ObjectName objName : queryResults)
278                     {
279                         String id = entry.getKey().toString()+(idx == 0 ? "" : ":"+idx);
280                         String name = queryString.equals(objName.toString()) ? "" : objName.toString();
281                         boolean repeat = Boolean.parseBoolean(values[2]);
282                         trigger.add(new JavaMonitorTrigger(objName, values[1], id, name, repeat));
283                     }   
284                 }
285            }
286         }
287     }
288     
289     /* ------------------------------------------------------------ */
290     /**
291      * @param value
292      * @return
293      */
294     private int getClassID(final Object value)
295     {
296         if (value == null)
297             return 0;
298         
299         if (value instanceof Byte || 
300             value instanceof Short ||
301             value instanceof Integer ||
302             value instanceof Long)
303             return 1;
304             
305         if (value instanceof Float ||
306             value instanceof Double)
307             return 2;
308         
309         if (value instanceof Boolean)
310             return 3;
311 
312         return 4; // String
313     }
314 
315     /* ------------------------------------------------------------ */
316     /**
317      * @return
318      * @throws Exception 
319      */
320     private String getServerIP()
321         throws Exception
322     {
323         Socket s = null;
324         try {
325             if (getProperty("http.proxyHost") != null)
326             {
327                 s = new Socket(getProperty("http.proxyHost"),
328                                parseInt(getProperty("http.proxyPort", "80")));
329             } 
330             else
331             {
332                 int port = 80;
333                 
334                 URL url = new URL(_url);
335                 if (url.getPort() != -1) {
336                     port = url.getPort();
337                 }
338                 s = new Socket(url.getHost(), port);
339             }
340             return s.getLocalAddress().getHostAddress();
341         }
342         finally
343         {
344             try
345             {
346                 if (s != null)
347                     s.close();
348             } 
349             catch (IOException ex)
350             {
351                 LOG.ignore(ex);
352             }
353         }
354     }
355     
356     /* ------------------------------------------------------------ */
357     public Integer getHttpPort() 
358     {       
359         Collection<ObjectName> connectors = null;
360         MBeanServerConnection service;
361         try
362         {
363             service = JMXMonitor.getServiceConnection();
364 
365             connectors = service.queryNames(new ObjectName("org.eclipse.jetty.nio:type=selectchannelconnector,*"), null);
366             if (connectors != null && connectors.size() > 0)
367             {
368                 Integer lowest = Integer.MAX_VALUE;
369                 for (final ObjectName connector : connectors) {
370                     lowest = (Integer)service.getAttribute(connector, "port");
371                 }
372         
373                 if (lowest < Integer.MAX_VALUE)
374                     return lowest;
375             }
376         }
377         catch (Exception ex)
378         {
379             LOG.debug(ex);
380         }
381         
382         return 0;
383     }
384 
385     /* ------------------------------------------------------------ */
386     /**
387      * @param param
388      * @return
389      * @throws IOException
390      * @throws NullPointerException 
391      * @throws MalformedObjectNameException 
392      */
393     private ObjectName[] queryNames(ObjectName param) 
394         throws IOException, MalformedObjectNameException
395     {
396         ObjectName[] result = null;
397         
398         MBeanServerConnection connection = JMXMonitor.getServiceConnection();
399         Set names = connection.queryNames(param, null);
400         if (names != null && names.size() > 0)
401         {
402             result = new ObjectName[names.size()];
403             
404             int idx = 0;
405             for(Object name : names)
406             {
407                 if (name instanceof ObjectName)
408                     result[idx++] = (ObjectName)name;
409                 else
410                     result[idx++] = new ObjectName(name.toString());
411             }
412         }
413         
414         return result;
415     }
416     
417     private ObjectName[] queryNames(String param) 
418         throws IOException, MalformedObjectNameException
419     {
420         return queryNames(new ObjectName(param));
421     }
422 
423  }