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.HttpClient;
39  import org.eclipse.jetty.client.api.ContentResponse;
40  import org.eclipse.jetty.client.util.BytesContentProvider;
41  import org.eclipse.jetty.http.HttpStatus;
42  import org.eclipse.jetty.monitor.JMXMonitor;
43  import org.eclipse.jetty.monitor.jmx.EventNotifier;
44  import org.eclipse.jetty.monitor.jmx.EventState;
45  import org.eclipse.jetty.monitor.jmx.EventState.TriggerState;
46  import org.eclipse.jetty.monitor.jmx.EventTrigger;
47  import org.eclipse.jetty.monitor.jmx.MonitorAction;
48  import org.eclipse.jetty.monitor.triggers.AggregateEventTrigger;
49  import org.eclipse.jetty.util.log.Log;
50  import org.eclipse.jetty.util.log.Logger;
51  import org.eclipse.jetty.util.thread.QueuedThreadPool;
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          QueuedThreadPool executor = new QueuedThreadPool();
87          executor.setName(executor.getName() + "-monitor");
88          _client = new HttpClient();
89          _client.setExecutor(executor);
90          
91          try
92          {
93              _client.start();
94              _srvip = getServerIP();
95          }
96          catch (Exception ex)
97          {
98              LOG.debug(ex);
99          }
100         
101         sendData(new Properties());
102      }
103 
104     /* ------------------------------------------------------------ */
105     /**
106      * @see org.eclipse.jetty.monitor.jmx.MonitorAction#execute(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
107      */
108     @Override
109     public void execute(EventTrigger trigger, EventState<?> state, long timestamp)
110     {
111         exec(trigger, state, timestamp);
112     }
113 
114     /* ------------------------------------------------------------ */
115     /**
116      * @param trigger
117      * @param state
118      * @param timestamp
119      */
120     private <T> void exec(EventTrigger trigger, EventState<T> state, long timestamp)
121     {
122         Collection<TriggerState<T>> trs = state.values();
123         
124         Properties data = new Properties();
125         for (TriggerState<T> ts :  trs)
126         {
127             Object value = ts.getValue();
128 
129             StringBuffer buffer = new StringBuffer();
130             buffer.append(value == null ? "" : value.toString());
131             buffer.append("|");
132             buffer.append(getClassID(value));
133             buffer.append("||");
134             buffer.append(ts.getDescription());
135             
136             data.setProperty(ts.getID(), buffer.toString());
137             
138             try
139             {
140                 sendData(data);
141             }
142             catch (Exception ex)
143             {
144                 LOG.debug(ex);
145             }
146         }
147      }
148     
149     /* ------------------------------------------------------------ */
150     /**
151      * @param data
152      * @throws Exception 
153      */
154     private void sendData(Properties data)
155         throws Exception
156     {
157         data.put("account", _uuid);
158         data.put("appserver", "Jetty");
159         data.put("localIp", _srvip);
160         if (_appid == null)
161             data.put("lowestPort", getHttpPort());
162         else
163             data.put("lowestPort", _appid);
164         if (_session != null)
165             data.put("session", _session);
166         
167         Properties response = sendRequest(data);
168         
169         parseResponse(response);
170     }
171 
172     /* ------------------------------------------------------------ */
173     /**
174      * @param request
175      * @return
176      * @throws Exception 
177      */
178     private Properties sendRequest(Properties request)
179         throws Exception
180     {
181         ByteArrayOutputStream reqStream = null;
182         ByteArrayInputStream resStream = null;
183         Properties response = null;
184     
185         try {
186             reqStream = new ByteArrayOutputStream();
187             request.storeToXML(reqStream,null);
188             
189             ContentResponse r3sponse = _client.POST(_url)
190                 .header("Connection","close")
191                 .content(new BytesContentProvider(reqStream.toByteArray()))
192                 .send();
193             
194                         
195             if (r3sponse.getStatus() == HttpStatus.OK_200)
196             {
197                 response = new Properties();
198                 resStream = new ByteArrayInputStream(r3sponse.getContent());
199                 response.loadFromXML(resStream);               
200             }
201         }
202         finally
203         {
204             try
205             {
206                 if (reqStream != null)
207                     reqStream.close();
208             }
209             catch (IOException ex)
210             {
211                 LOG.ignore(ex);
212             }
213             
214             try
215             {
216                 if (resStream != null)
217                     resStream.close();
218             }
219             catch (IOException ex)
220             {
221                 LOG.ignore(ex);
222             }
223         }
224         
225         return response;    
226     }
227     
228     /* ------------------------------------------------------------ */
229     private void parseResponse(Properties response)
230     {
231         if (response.get("onhold") != null)
232             throw new Error("Suspended");
233         
234 
235         if (response.get("session") != null)
236         {
237             _session = (String) response.remove("session");
238 
239             AggregateEventTrigger trigger = (AggregateEventTrigger)getTrigger();
240 
241             String queryString;
242             ObjectName[] queryResults;
243             for (Map.Entry<Object, Object> entry : response.entrySet())
244             {
245                 String[] values = ((String) entry.getValue()).split("\\|");
246 
247                 queryString = values[0];
248                 if (queryString.startsWith("com.javamonitor.openfire"))
249                     continue;
250                 
251                 if (queryString.startsWith("com.javamonitor"))
252                 {
253                     queryString = "org.eclipse.jetty.monitor.integration:type=javamonitortools,id=0";
254                 }
255                 
256                 queryResults = null;
257                 try
258                 {
259                     queryResults = queryNames(queryString);
260                 }
261                 catch (IOException e)
262                 {
263                     LOG.debug(e);
264                 }
265                 catch (MalformedObjectNameException e)
266                 {
267                     LOG.debug(e);
268                 }
269                 
270                 if (queryResults != null)
271                 {
272                     int idx = 0;
273                     for(ObjectName objName : queryResults)
274                     {
275                         String id = entry.getKey().toString()+(idx == 0 ? "" : ":"+idx);
276                         String name = queryString.equals(objName.toString()) ? "" : objName.toString();
277                         boolean repeat = Boolean.parseBoolean(values[2]);
278                         trigger.add(new JavaMonitorTrigger(objName, values[1], id, name, repeat));
279                     }   
280                 }
281            }
282         }
283     }
284     
285     /* ------------------------------------------------------------ */
286     /**
287      * @param value
288      * @return
289      */
290     private int getClassID(final Object value)
291     {
292         if (value == null)
293             return 0;
294         
295         if (value instanceof Byte || 
296             value instanceof Short ||
297             value instanceof Integer ||
298             value instanceof Long)
299             return 1;
300             
301         if (value instanceof Float ||
302             value instanceof Double)
303             return 2;
304         
305         if (value instanceof Boolean)
306             return 3;
307 
308         return 4; // String
309     }
310 
311     /* ------------------------------------------------------------ */
312     /**
313      * @return
314      * @throws Exception 
315      */
316     private String getServerIP()
317         throws Exception
318     {
319         Socket s = null;
320         try {
321             if (getProperty("http.proxyHost") != null)
322             {
323                 s = new Socket(getProperty("http.proxyHost"),
324                                parseInt(getProperty("http.proxyPort", "80")));
325             } 
326             else
327             {
328                 int port = 80;
329                 
330                 URL url = new URL(_url);
331                 if (url.getPort() != -1) {
332                     port = url.getPort();
333                 }
334                 s = new Socket(url.getHost(), port);
335             }
336             return s.getLocalAddress().getHostAddress();
337         }
338         finally
339         {
340             try
341             {
342                 if (s != null)
343                     s.close();
344             } 
345             catch (IOException ex)
346             {
347                 LOG.ignore(ex);
348             }
349         }
350     }
351     
352     /* ------------------------------------------------------------ */
353     public Integer getHttpPort() 
354     {       
355         Collection<ObjectName> connectors = null;
356         MBeanServerConnection service;
357         try
358         {
359             service = JMXMonitor.getServiceConnection();
360 
361             connectors = service.queryNames(new ObjectName("org.eclipse.jetty.nio:type=selectchannelconnector,*"), null);
362             if (connectors != null && connectors.size() > 0)
363             {
364                 Integer lowest = Integer.MAX_VALUE;
365                 for (final ObjectName connector : connectors) {
366                     lowest = (Integer)service.getAttribute(connector, "port");
367                 }
368         
369                 if (lowest < Integer.MAX_VALUE)
370                     return lowest;
371             }
372         }
373         catch (Exception ex)
374         {
375             LOG.debug(ex);
376         }
377         
378         return 0;
379     }
380 
381     /* ------------------------------------------------------------ */
382     /**
383      * @param param
384      * @return
385      * @throws IOException
386      * @throws NullPointerException 
387      * @throws MalformedObjectNameException 
388      */
389     private ObjectName[] queryNames(ObjectName param) 
390         throws IOException, MalformedObjectNameException
391     {
392         ObjectName[] result = null;
393         
394         MBeanServerConnection connection = JMXMonitor.getServiceConnection();
395         Set names = connection.queryNames(param, null);
396         if (names != null && names.size() > 0)
397         {
398             result = new ObjectName[names.size()];
399             
400             int idx = 0;
401             for(Object name : names)
402             {
403                 if (name instanceof ObjectName)
404                     result[idx++] = (ObjectName)name;
405                 else
406                     result[idx++] = new ObjectName(name.toString());
407             }
408         }
409         
410         return result;
411     }
412     
413     private ObjectName[] queryNames(String param) 
414         throws IOException, MalformedObjectNameException
415     {
416         return queryNames(new ObjectName(param));
417     }
418 
419  }