1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package org.apache.jmeter.samplers; 20 21 import org.apache.jmeter.util.JMeterUtils; 22 import org.apache.jorphan.logging.LoggingManager; 23 import org.apache.log.Logger; 24 25 import java.io.Serializable; 26 import java.rmi.RemoteException; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * Implements batch reporting for remote testing. 34 * 35 */ 36 public class StatisticalSampleSender implements SampleSender, Serializable { 37 private static final Logger log = LoggingManager.getLoggerForClass(); 38 39 private static final int DEFAULT_NUM_SAMPLE_THRESHOLD = 100; 40 41 private static final long DEFAULT_TIME_THRESHOLD = 60000L; 42 43 private RemoteSampleListener listener; 44 45 private List sampleStore = new ArrayList(); 46 47 private Map sampleTable = new HashMap(); 48 49 private int numSamplesThreshold; 50 51 private int sampleCount; 52 53 private long timeThreshold; 54 55 private long batchSendTime = -1; 56 57 public StatisticalSampleSender(){ 58 log.warn("Constructor only intended for use in testing"); 59 } 60 61 62 /** 63 * Constructor 64 * 65 * @param listener that the List of sample events will be sent to. 66 */ 67 StatisticalSampleSender(RemoteSampleListener listener) { 68 this.listener = listener; 69 init(); 70 log.info("Using batching for this run." + " Thresholds: num=" 71 + numSamplesThreshold + ", time=" + timeThreshold); 72 } 73 74 /** 75 * Checks for the Jmeter properties num_sample_threshold and time_threshold, 76 * and assigns defaults if not found. 77 */ 78 private void init() { 79 this.numSamplesThreshold = JMeterUtils.getPropDefault( 80 "num_sample_threshold", DEFAULT_NUM_SAMPLE_THRESHOLD); 81 this.timeThreshold = JMeterUtils.getPropDefault("time_threshold", 82 DEFAULT_TIME_THRESHOLD); 83 } 84 85 /** 86 * Checks if any sample events are still present in the sampleStore and 87 * sends them to the listener. Informs the listener of the testended. 88 */ 89 public void testEnded() { 90 try { 91 if (sampleStore.size() != 0) { 92 sendBatch(); 93 } 94 listener.testEnded(); 95 } catch (RemoteException err) { 96 log.warn("testEnded()", err); 97 } 98 } 99 100 /** 101 * Checks if any sample events are still present in the sampleStore and 102 * sends them to the listener. Informs the listener of the testended. 103 * 104 * @param host the hostname that the test has ended on. 105 */ 106 public void testEnded(String host) { 107 try { 108 if (sampleStore.size() != 0) { 109 sendBatch(); 110 } 111 listener.testEnded(host); 112 } catch (RemoteException err) { 113 log.warn("testEnded(hostname)", err); 114 } 115 } 116 117 /** 118 * Stores sample events untill either a time or sample threshold is 119 * breached. Both thresholds are reset if one fires. If only one threshold 120 * is set it becomes the only value checked against. When a threhold is 121 * breached the list of sample events is sent to a listener where the event 122 * are fired locally. 123 * 124 * @param e a Sample Event 125 */ 126 public void sampleOccurred(SampleEvent e) { 127 synchronized (sampleStore) { 128 // Locate the statistical sample colector 129 String key = StatisticalSampleResult.getKey(e); 130 StatisticalSampleResult statResult = (StatisticalSampleResult) sampleTable 131 .get(key); 132 if (statResult == null) { 133 statResult = new StatisticalSampleResult(e.getResult()); 134 // store the new statistical result collector 135 sampleTable.put(key, statResult); 136 // add a new wrapper samplevent 137 sampleStore 138 .add(new SampleEvent(statResult, e.getThreadGroup())); 139 } 140 statResult.add(e.getResult()); 141 sampleCount++; 142 if (numSamplesThreshold != -1) { 143 if (sampleCount >= numSamplesThreshold) { 144 try { 145 if (log.isDebugEnabled()) { 146 log.debug("Firing sample"); 147 } 148 sendBatch(); 149 } catch (RemoteException err) { 150 log.warn("sampleOccurred", err); 151 } 152 } 153 } 154 155 if (timeThreshold != -1) { 156 long now = System.currentTimeMillis(); 157 // Checking for and creating initial timestamp to cheak against 158 if (batchSendTime == -1) { 159 this.batchSendTime = now + timeThreshold; 160 } 161 162 if (batchSendTime < now) { 163 try { 164 if (log.isDebugEnabled()) { 165 log.debug("Firing time"); 166 } 167 sendBatch(); 168 this.batchSendTime = now + timeThreshold; 169 } catch (RemoteException err) { 170 log.warn("sampleOccurred", err); 171 } 172 } 173 } 174 } 175 } 176 177 private void sendBatch() throws RemoteException { 178 if (sampleStore.size() > 0) { 179 listener.processBatch(sampleStore); 180 sampleStore.clear(); 181 sampleTable.clear(); 182 sampleCount = 0; 183 } 184 } 185 }