View Javadoc

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