/* * Copyright (c) 2014, Paessler AG <support@paessler.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.paessler.prtg.jmx.tasks; import com.google.gson.*; import com.paessler.prtg.jmx.Logger; import com.paessler.prtg.jmx.ProbeContext; import com.paessler.prtg.jmx.definitions.SensorDefinition; import com.paessler.prtg.jmx.mbean.PRTGInterface; import com.paessler.prtg.jmx.network.Announcement; import com.paessler.prtg.jmx.network.NetworkWrapper; import com.paessler.prtg.jmx.network.Tasks; import com.paessler.prtg.jmx.responses.DataResponse; import com.paessler.prtg.jmx.sensors.Sensor; import com.paessler.prtg.util.TimingUtility; import javax.servlet.ServletContext; import org.apache.http.client.HttpResponseException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TimerTask; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TaskFetcherTask extends TimerTask { public static final String EMPTY_TASKLIST = "[]"; final private ServletContext mServletContext; final private ProbeContext mProbeContext; private ExecutorService executor = null; private boolean myExecutor = false; private PRTGInterface prtgMBean = null; // ----------------------------------------------------- protected List<DataResponse> resultList = null; // ---------------------------- public List<DataResponse> getResultList() { return resultList; } // ---------------------------- protected void setResultList(List<DataResponse> resultList) { this.resultList = resultList; } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- private boolean reRunAnnouncement = true; public void setRerunAnnouncement(boolean val) {reRunAnnouncement = val;} public boolean getReRunAnnouncement() {return reRunAnnouncement;} public boolean sendAnnouncement(ProbeContext context){ boolean retVal = false; try { List<SensorDefinition> definitions = context.getSensorDefinitionsListHack(); Announcement announcement = new Announcement(context.getProbeName(), context.getVersionString(), context.getBaseInterval(), definitions); String url = announcement.buildUrl(context); int maxtries = 5; for(int retryAttempts = 0;!retVal && retryAttempts < maxtries; ++retryAttempts){ try { String postBody = announcement.toString(); if(context.getDebugLevel() > 0){ Logger.log("Sending: "+url+" " + postBody); } NetworkWrapper.post(url, postBody); retVal = true; reRunAnnouncement = false; } catch (HttpResponseException he) { Logger.log(he.getLocalizedMessage()); if(he.getStatusCode() < 500){ Thread.sleep(10000*retryAttempts); } else{ retryAttempts = maxtries; } } catch (Exception e) { Logger.log(e.getLocalizedMessage()); retryAttempts = maxtries; } } } catch (Throwable e) { Logger.log("Cought Throwable in TaskFetcherTask.run(). "+e.getMessage()); e.printStackTrace(); } return retVal; } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- public synchronized void addDataResponse(Sensor sensor, DataResponse response){ List<DataResponse> list = getResultList(); if(list != null){ list.add(response); } } // ----------------------------------------------------- public TaskFetcherTask(ServletContext context, ProbeContext probeContext, ExecutorService execsrvc) { prtgMBean = PRTGInterface.getAndRegisterBean(PRTGInterface.getDefaultBeanName()); mServletContext = context; mProbeContext = probeContext; if(execsrvc != null){ executor = execsrvc; } else { // executor = Executors.newFixedThreadPool(mProbeContext.workerThreads); executor = Executors.newFixedThreadPool(2); myExecutor = true; } setResultList(new Vector<DataResponse>()); } public void cleanup(){ if(prtgMBean != null){ PRTGInterface.unregisterBean(prtgMBean); } } // ----------------------------------------------------- public void finalizer(){ cleanup(); if(myExecutor && executor != null){ executor.shutdown(); } } // ----------------------------------------------------- private String currJson = null; private Map<Integer, Sensor> sensorMap = null; private Map<Integer, Sensor> getSensorMap(){ return sensorMap;} protected boolean addSensor(Sensor sensor){ boolean retVal = false; if(sensorMap != null){ Integer key = sensor.getSensorid(); Sensor ret = sensorMap.put(key, sensor); retVal = true; } return retVal; } // ----------------------------------------------------- protected Sensor sensorFactory(JsonObject json) { Sensor retVal = null; String kind = json.get("kind").getAsString(); int id = json.get("sensorid").getAsInt(); try { retVal = mProbeContext.sensorFactory(kind); if(retVal != null){ retVal.loadFromJson(json); } } catch (Exception e) { Logger.log("Error creating sensor from JSON: " +json + " " + e.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 0){ e.printStackTrace(); } } return retVal; } // ----------------------------------------------------- private Map<Integer, Sensor> getSensors(String json){ if(currJson != null && sensorMap != null && json.equals(currJson)){ return sensorMap; } JsonParser parser = new JsonParser(); // JsonElement top = parser.parse(json); JsonElement top = null; try { top = parser.parse(json); } catch (Throwable e) { Logger.log(e.getClass().getName()+": " + e.getLocalizedMessage()+"\nJSON>>"+json+"<<\n"); return sensorMap; } JsonArray tasksArray = top.getAsJsonArray(); Sensor sensor = null; int len = tasksArray.size(); Map<Integer, Sensor> oldSensorMap = sensorMap; sensorMap = new ConcurrentHashMap<Integer, Sensor>(len); // sensorMap = new ConcurrentSkipListMap<Integer, Sensor>(); JsonObject json4Sensor = null; // String kind = null; int id = -1; for (int i = 0; i < len; i++) { json4Sensor = tasksArray.get(i).getAsJsonObject(); id = json4Sensor.get("sensorid").getAsInt(); sensor = null; if(oldSensorMap != null){ sensor = oldSensorMap.get(id); } if(sensor == null || !sensor.isSame(json4Sensor)){ sensor = sensorFactory(json4Sensor); } if(sensor != null ){ addSensor(sensor); } } currJson = json; return sensorMap; } // -------------------------------------------------- private Map<Integer, Sensor> getSensors(){ Map<Integer, Sensor> retVal = null; String url = Tasks.buildUrl(mProbeContext); String json = null; boolean nocontact = false; try { json = NetworkWrapper.fetch(url); } catch (IOException e) { nocontact = true; setRerunAnnouncement(true); Logger.log(e.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 0){ e.printStackTrace(); } } // If we lost contact with the server, probe anyways and cache results. if(nocontact){ retVal = getSensorMap(); } else{ if (json != null && !json.equals(EMPTY_TASKLIST)) { if(mProbeContext.getDebugLevel() > 0){ Logger.log("Debug task: " + url+" "+json); } retVal = getSensors(json); } } prtgMBean.addQueryCount(1); return retVal; } // ----------------------------------------------------- protected void sendResponse(List<DataResponse> responseList){ String dataUrl = mProbeContext.getURLPrefix("/probe/data"); if (responseList.size() > 0) { Gson gson = new Gson(); String dataJson = gson.toJson(responseList); if(mProbeContext.getDebugLevel() > 0){ Logger.log("Debug posting sensor data: " + dataUrl+" "+dataJson); } try { NetworkWrapper.post(dataUrl, dataJson); responseList.clear(); } catch (Exception e) { Logger.log("Error sending data: " + e.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 1){ e.printStackTrace(); } } } // Until we have timestamp, no caching if(!mProbeContext.isTimestampEnabled()) responseList.clear(); } // ----------------------------------------------------- // @Override public void runMT() { TimingUtility sensorexectimer = new TimingUtility(); TimingUtility sensorcreationtimer = new TimingUtility(); TimingUtility sensoruploadtimer = new TimingUtility(); boolean updatestats = false; sensorcreationtimer.start(); Map<Integer, Sensor> sensors = getSensors(); sensorcreationtimer.stop(); if(sensors != null && sensors.size() > 0){ prtgMBean.setSensorCount(getSensorMap().size()); // Run the probe List<Future<?>> futures = new ArrayList<Future<?>> (sensors.size()); sensorexectimer.start(); for (Sensor sensor: sensors.values()) { sensor.setControllerTask(this); futures.add( executor.submit(sensor)); } for (Future<?> f : futures) { try { // if(!f.isDone()) if(f != null) f.get(); //blocks until the runnable completes } catch (InterruptedException ie) { Logger.log("InterruptedException: on["+f+"] " + ie.getLocalizedMessage()); } catch (ExecutionException ee) { Logger.log("ExecutionException: on["+f+"] " + ee.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 1){ ee.printStackTrace(); } } } updatestats = true; sensorexectimer.stop(); Logger.log("Sensor Creation:" + sensorcreationtimer +", Data Collection : " + sensorexectimer); prtgMBean.addQueryCount(1); prtgMBean.addSenorCreationTime(sensorcreationtimer.getElapsed()); prtgMBean.addExecutionTime(sensorexectimer.getElapsed()); } else{ Logger.log("Sensor Creation Yeilded nothing to do[empty list of sensors]"); sensorexectimer.stop(); } try{ sensoruploadtimer.start(); sendResponse(getResultList()); sensoruploadtimer.stop(); } catch (Exception e) { Logger.log("Error sending data: " + e.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 1){ e.printStackTrace(); } } if(updatestats){ Logger.log("Sensor Creation:" + sensorcreationtimer +", Data Collection : " + sensorexectimer); prtgMBean.addQueryCount(1); prtgMBean.addSenorCreationTime(sensorcreationtimer.getElapsed()); prtgMBean.addExecutionTime(sensorexectimer.getElapsed()); prtgMBean.addUploadTime(sensoruploadtimer.getElapsed()); } } // ----------------------------------------------------- // @Override public void runST() { Map<Integer, Sensor> sensors = getSensors(); setResultList(new ArrayList<DataResponse>()); for (Sensor sensor: sensors.values()) { DataResponse response = sensor.go(); if (response != null) addDataResponse(sensor, response); } try{ sendResponse(getResultList()); } catch (Exception e) { Logger.log("Error sending data: " + e.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 1){ e.printStackTrace(); } } } // ----------------------------------------------------- @Override public void run() { try{ if(getReRunAnnouncement()){ if(!sendAnnouncement(mProbeContext)){ // Announcement failed, retry next iteration return; } } runMT(); } catch(Error err){ Logger.log("Error run: " + err.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 0){ err.printStackTrace(); } } catch(Throwable t){ Logger.log("Throwable in run: " + t.getLocalizedMessage()); if(mProbeContext.getDebugLevel() > 0){ t.printStackTrace(); } } } }