001package jmri.implementation.decorators; 002 003import jmri.*; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007import java.beans.PropertyChangeEvent; 008import java.beans.PropertyChangeListener; 009 010/** 011 * Timeout decorator implementation for reporters. 012 * <p> 013 * This decorator causes the current report to be reset to nullified after a 014 * preset time period. This is to be used for reporter hardware that reports 015 * a value, but never reports the value is cleared (e.g. most RFID readers). 016 * <hr> 017 * This file is part of JMRI. 018 * <p> 019 * based on TimeoutRfidReporter originally implemented by Matthew Harris 020 * <p> 021 * JMRI is free software; you can redistribute it and/or modify it under the 022 * terms of version 2 of the GNU General Public License as published by the Free 023 * Software Foundation. See the "COPYING" file for a copy of this license. 024 * <p> 025 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 026 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 027 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 028 * Based 029 * @author Matthew Harris Copyright (C) 2014 030 * @author Paul Bender Copyright (C) 2020 031 * @since 4.19.4 032 */ 033public class TimeoutReporter extends AbstractNamedBeanDecorator implements Reporter, IdTagListener,PropertyChangeListener { 034 035 /** 036 * The reporter this object is a decorator for 037 */ 038 private Reporter reporter; 039 040 041 /** 042 * Timeout in ms 043 */ 044 private static final int TIMEOUT = 2000; 045 046 /** 047 * Time when something was last reported by this object 048 */ 049 private long whenLastReported = 0; 050 051 /** 052 * Reference to the timeout thread for this object 053 */ 054 private TimeoutThread timeoutThread = null; 055 056 public TimeoutReporter(Reporter reporter) { 057 super(reporter); 058 this.reporter = reporter; 059 this.reporter.addPropertyChangeListener(this); 060 } 061 062 @Override 063 public Object getLastReport() { 064 return reporter.getLastReport(); 065 } 066 067 @Override 068 public Object getCurrentReport() { 069 return reporter.getCurrentReport(); 070 } 071 072 @Override 073 public void setReport(Object r) { 074 reporter.setReport(r); 075 } 076 077 @Override 078 public int getState() { 079 return reporter.getState(); 080 } 081 082 @Override 083 public void dispose() { 084 super.dispose(); 085 reporter.dispose(); 086 } 087 088 @Override 089 public void setState(int i) throws JmriException { 090 reporter.setState(i); 091 } 092 093 @Override 094 public void notify(IdTag r) { 095 if(reporter instanceof IdTagListener ){ 096 ((IdTagListener)reporter).notify(r); 097 } 098 } 099 100 /** 101 * {@inheritDoc} 102 * 103 * Intercepts property change events from the underlying reporter 104 * and forwards them to property change listeners for this reporter. 105 */ 106 @Override 107 public void propertyChange(PropertyChangeEvent evt) { 108 log.debug("event received {}",evt); 109 if(evt.getPropertyName().equals("currentReport") && 110 evt.getNewValue()!=null ){ 111 whenLastReported = System.currentTimeMillis(); 112 if (timeoutThread == null) { 113 timeoutThread = new TimeoutThread(); 114 timeoutThread.start(); 115 } 116 } 117 // fire off the property change for listeners of this TimeoutReporter. 118 firePropertyChange(evt.getPropertyName(),evt.getOldValue(),evt.getNewValue()); 119 } 120 121 private void cleanUpTimeout() { 122 log.debug("Cleanup timeout thread for {}",getSystemName()); 123 timeoutThread = null; 124 } 125 126 private class TimeoutThread extends Thread { 127 128 TimeoutThread() { 129 super(); 130 this.setName("Timeout-" + getSystemName()); 131 } 132 133 @Override 134// @SuppressWarnings("SleepWhileInLoop") 135 public void run() { 136 while ((whenLastReported + TIMEOUT) > System.currentTimeMillis()) { 137 try { 138 Thread.sleep(100); 139 } catch (InterruptedException ex) { 140 } 141 } 142 reporter.setReport(null); 143 log.debug("Timeout-{}", getSystemName()); 144 cleanUpTimeout(); 145 } 146 } 147 148 private static final Logger log = LoggerFactory.getLogger(TimeoutReporter.class); 149 150}