View Javadoc

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