001 package com.croftsoft.core.net.http.msg; 002 003 import java.io.*; 004 import java.net.*; 005 006 import com.croftsoft.core.io.Parser; 007 import com.croftsoft.core.lang.NullArgumentException; 008 import com.croftsoft.core.lang.lifecycle.Lifecycle; 009 import com.croftsoft.core.math.MathConstants; 010 import com.croftsoft.core.net.http.HttpLib; 011 import com.croftsoft.core.util.loop.FixedDelayLoopGovernor; 012 import com.croftsoft.core.util.loop.Loopable; 013 import com.croftsoft.core.util.loop.Looper; 014 import com.croftsoft.core.util.queue.Queue; 015 016 /********************************************************************* 017 * Polls a server for messages and downloads them to a local queue. 018 * 019 * @version 020 * 2003-06-12 021 * @since 022 * 2000-04-27 023 * @author 024 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 025 *********************************************************************/ 026 027 public final class HttpMessagePoller 028 implements Lifecycle 029 ////////////////////////////////////////////////////////////////////// 030 ////////////////////////////////////////////////////////////////////// 031 { 032 033 public static final long DEFAULT_POLLING_PERIOD_MIN 034 = MathConstants.MILLISECONDS_PER_SECOND; 035 036 public static final long DEFAULT_POLLING_PERIOD_MAX 037 = MathConstants.MILLISECONDS_PER_DAY; 038 039 public static final long DEFAULT_POLLING_PERIOD_INIT 040 = DEFAULT_POLLING_PERIOD_MIN; 041 042 public static final double DEFAULT_POLLING_PERIOD_MULT 043 = 1.1; 044 045 public static final double DEFAULT_POLLING_PERIOD_DIVI 046 = 1.1; 047 048 public static final long DEFAULT_POLLING_PERIOD_INCR 049 = MathConstants.MILLISECONDS_PER_SECOND; 050 051 public static final String THREAD_NAME = "HttpMessagePoller"; 052 053 public static final int THREAD_PRIORITY = Thread.MIN_PRIORITY; 054 055 public static final boolean USE_DAEMON_THREAD = true; 056 057 // 058 059 private static final boolean DEBUG = false; 060 061 // 062 063 private final URL url; 064 065 private final String userAgent; 066 067 private final String contentType; 068 069 private final Parser parser; 070 071 private final Looper looper; 072 073 private final Queue incomingQueue; 074 075 private final long pollingPeriodMin; 076 077 private final long pollingPeriodMax; 078 079 private final double pollingPeriodMult; 080 081 private final double pollingPeriodDivi; 082 083 private final long pollingPeriodIncr; 084 085 // 086 087 private byte [ ] requestBytes; 088 089 private long pollingPeriod; 090 091 ////////////////////////////////////////////////////////////////////// 092 // constructor methods 093 ////////////////////////////////////////////////////////////////////// 094 095 /********************************************************************* 096 * All polling period values are in milliseconds. 097 * 098 * @param pollingPeriodIncr 099 * 100 * Minimum incremental change whenever the polling period is 101 * increased or decreased, regardless of the pollingPeriodMult 102 * or pollingPeriodDivi value. 103 *********************************************************************/ 104 public HttpMessagePoller ( 105 URL url, 106 String userAgent, 107 String contentType, 108 byte [ ] requestBytes, 109 Parser parser, 110 Queue incomingQueue, 111 long pollingPeriodMin, 112 long pollingPeriodMax, 113 long pollingPeriodInit, 114 double pollingPeriodMult, 115 double pollingPeriodDivi, 116 long pollingPeriodIncr ) 117 ////////////////////////////////////////////////////////////////////// 118 { 119 NullArgumentException.check ( this.url = url ); 120 121 NullArgumentException.check ( this.userAgent = userAgent ); 122 123 NullArgumentException.check ( this.contentType = contentType ); 124 125 NullArgumentException.check ( this.parser = parser ); 126 127 NullArgumentException.check ( this.incomingQueue = incomingQueue ); 128 129 setRequestBytes ( requestBytes ); 130 131 if ( pollingPeriodMin < 0 ) 132 { 133 throw new IllegalArgumentException ( "pollingPeriodMin < 0" ); 134 } 135 136 if ( pollingPeriodMax < pollingPeriodMin ) 137 { 138 throw new IllegalArgumentException ( 139 "pollingPeriodMax < pollingPeriodMin" ); 140 } 141 142 if ( pollingPeriodInit < pollingPeriodMin ) 143 { 144 throw new IllegalArgumentException ( 145 "pollingPeriodInit < pollingPeriodMin" ); 146 } 147 148 if ( pollingPeriodInit > pollingPeriodMax ) 149 { 150 throw new IllegalArgumentException ( 151 "pollingPeriodInit > pollingPeriodMax" ); 152 } 153 154 if ( pollingPeriodMult < 1.0 ) 155 { 156 throw new IllegalArgumentException ( "pollingPeriodMult < 1.0" ); 157 } 158 159 if ( pollingPeriodDivi < 1.0 ) 160 { 161 throw new IllegalArgumentException ( "pollingPeriodDivi < 1.0" ); 162 } 163 164 if ( pollingPeriodIncr < 0 ) 165 { 166 throw new IllegalArgumentException ( "pollingPeriodIncr < 0" ); 167 } 168 169 looper = new Looper ( 170 new Loopable ( ) 171 { 172 public boolean loop ( ) 173 { 174 return HttpMessagePoller.this.loop ( ); 175 } 176 }, 177 new FixedDelayLoopGovernor ( pollingPeriodInit, 0 ), 178 null, 179 THREAD_NAME, 180 THREAD_PRIORITY, 181 USE_DAEMON_THREAD ); 182 183 this.pollingPeriodMin = pollingPeriodMin; 184 185 this.pollingPeriodMax = pollingPeriodMax; 186 187 this.pollingPeriodMult = pollingPeriodMult; 188 189 this.pollingPeriodDivi = pollingPeriodDivi; 190 191 this.pollingPeriodIncr = pollingPeriodIncr; 192 193 pollingPeriod = pollingPeriodInit; 194 } 195 196 /********************************************************************* 197 * Convenience constructor using default polling period values. 198 *********************************************************************/ 199 public HttpMessagePoller ( 200 URL url, 201 String userAgent, 202 String contentType, 203 byte [ ] requestBytes, 204 Parser contentParser, 205 Queue incomingQueue ) 206 ////////////////////////////////////////////////////////////////////// 207 { 208 this ( 209 url, 210 userAgent, 211 contentType, 212 requestBytes, 213 contentParser, 214 incomingQueue, 215 DEFAULT_POLLING_PERIOD_MIN, 216 DEFAULT_POLLING_PERIOD_MAX, 217 DEFAULT_POLLING_PERIOD_INIT, 218 DEFAULT_POLLING_PERIOD_MULT, 219 DEFAULT_POLLING_PERIOD_DIVI, 220 DEFAULT_POLLING_PERIOD_INCR ); 221 } 222 223 ////////////////////////////////////////////////////////////////////// 224 // mutator methods 225 ////////////////////////////////////////////////////////////////////// 226 227 public void setRequestBytes ( byte [ ] requestBytes ) 228 ////////////////////////////////////////////////////////////////////// 229 { 230 NullArgumentException.check ( this.requestBytes = requestBytes ); 231 } 232 233 public synchronized long setPollingPeriod ( long pollingPeriod ) 234 ////////////////////////////////////////////////////////////////////// 235 { 236 if ( pollingPeriod < pollingPeriodMin ) 237 { 238 pollingPeriod = pollingPeriodMin; 239 } 240 241 if ( pollingPeriod > pollingPeriodMax ) 242 { 243 pollingPeriod = pollingPeriodMax; 244 } 245 246 this.pollingPeriod = pollingPeriod; 247 248 looper.setLoopGovernor ( 249 new FixedDelayLoopGovernor ( pollingPeriod, 0 ) ); 250 251 return pollingPeriod; 252 } 253 254 ////////////////////////////////////////////////////////////////////// 255 // lifecycle methods 256 ////////////////////////////////////////////////////////////////////// 257 258 public void init ( ) 259 ////////////////////////////////////////////////////////////////////// 260 { 261 looper.init ( ); 262 } 263 264 public void start ( ) 265 ////////////////////////////////////////////////////////////////////// 266 { 267 looper.start ( ); 268 } 269 270 public void stop ( ) 271 ////////////////////////////////////////////////////////////////////// 272 { 273 looper.stop ( ); 274 } 275 276 public void destroy ( ) 277 ////////////////////////////////////////////////////////////////////// 278 { 279 looper.destroy ( ); 280 } 281 282 ////////////////////////////////////////////////////////////////////// 283 // private methods 284 ////////////////////////////////////////////////////////////////////// 285 286 private boolean loop ( ) 287 ////////////////////////////////////////////////////////////////////// 288 { 289 try 290 { 291 Object response = HttpLib.post ( 292 url, 293 requestBytes, 294 userAgent, 295 contentType, 296 parser ); 297 298 if ( response != null ) 299 { 300 incomingQueue.append ( response ); 301 302 decreasePollingPeriod ( ); 303 } 304 else 305 { 306 increasePollingPeriod ( ); 307 } 308 309 return true; 310 } 311 catch ( Exception ex ) 312 { 313 ex.printStackTrace ( ); 314 315 increasePollingPeriod ( ); 316 317 return true; 318 } 319 } 320 321 private void increasePollingPeriod ( ) 322 ////////////////////////////////////////////////////////////////////// 323 { 324 long newPollingPeriod 325 = ( long ) ( pollingPeriod * pollingPeriodMult ); 326 327 if ( newPollingPeriod < pollingPeriod + pollingPeriodIncr ) 328 { 329 newPollingPeriod = pollingPeriod + pollingPeriodIncr; 330 } 331 332 if ( newPollingPeriod > pollingPeriodMax ) 333 { 334 newPollingPeriod = pollingPeriodMax; 335 } 336 337 if ( pollingPeriod != newPollingPeriod ) 338 { 339 if ( DEBUG ) 340 { 341 System.out.println ( 342 "Increasing polling period from " + pollingPeriod 343 + " to " + newPollingPeriod + " milliseconds." ); 344 } 345 346 looper.setLoopGovernor ( 347 new FixedDelayLoopGovernor ( newPollingPeriod, 0 ) ); 348 349 pollingPeriod = newPollingPeriod; 350 } 351 } 352 353 private void decreasePollingPeriod ( ) 354 ////////////////////////////////////////////////////////////////////// 355 { 356 long newPollingPeriod 357 = ( long ) ( pollingPeriod / pollingPeriodDivi ); 358 359 if ( newPollingPeriod > pollingPeriod - pollingPeriodIncr ) 360 { 361 newPollingPeriod = pollingPeriod - pollingPeriodIncr; 362 } 363 364 if ( newPollingPeriod < pollingPeriodMin ) 365 { 366 newPollingPeriod = pollingPeriodMin; 367 } 368 369 if ( pollingPeriod != newPollingPeriod ) 370 { 371 if ( DEBUG ) 372 { 373 System.out.println ( 374 "Decreasing polling period from " + pollingPeriod 375 + " to " + newPollingPeriod + " milliseconds." ); 376 } 377 378 looper.setLoopGovernor ( 379 new FixedDelayLoopGovernor ( newPollingPeriod, 0 ) ); 380 381 pollingPeriod = newPollingPeriod; 382 } 383 } 384 385 ////////////////////////////////////////////////////////////////////// 386 ////////////////////////////////////////////////////////////////////// 387 }