View Javadoc

1   /*
2    *  
3    *  Fosstrak LLRP Commander (www.fosstrak.org)
4    * 
5    *  Copyright (C) 2008 ETH Zurich
6    *
7    *  This program is free software: you can redistribute it and/or modify
8    *  it under the terms of the GNU General Public License as published by
9    *  the Free Software Foundation, either version 3 of the License, or
10   *  (at your option) any later version.
11   *
12   *  This program is distributed in the hope that it will be useful,
13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   *  GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License
18   *  along with this program.  If not, see <http://www.gnu.org/licenses/> 
19   *
20   */
21  
22  package org.fosstrak.llrp.adaptor.util;
23  
24  import java.rmi.RemoteException;
25  import java.util.LinkedList;
26  import java.util.List;
27  
28  import org.fosstrak.llrp.adaptor.AsynchronousNotifiable;
29  import org.fosstrak.llrp.adaptor.exception.LLRPRuntimeException;
30  
31  /**
32   * helper class to maintain a list of asynchronous message receivers. the 
33   * helper checks whether there are transmission exception, and if so then the 
34   * respective receivers get dropped after a certain number of erroneous 
35   * transmissions.
36   * @author swieland
37   *
38   */
39  public class AsynchronousNotifiableList implements AsynchronousNotifiable {
40  	
41  	/** a list with all the receivers of asynchronous messages. */
42  	private LinkedList<Receiver> receivers = new LinkedList<Receiver>();
43  	
44  	/** remove the receiver after this number of unsuccessful connection attempts. */
45  	public static final int NUM_NON_RECHABLE_ALLOWED = 3;
46  	
47  	/** erroneous receivers that will be removed during cleanup. */
48  	private LinkedList<Receiver> erroneous = null;
49  	
50  	/**
51  	 * internal wrapper class that helps counting the errors...
52  	 * @author sawielan
53  	 *
54  	 */
55  	private class Receiver {
56  		// the number of errors occurred.
57  		private int errors = 0;
58  		
59  		// the receiver.
60  		private AsynchronousNotifiable receiver = null;
61  		
62  		/**
63  		 * creates a wrapper class.
64  		 * @param receiver the receiver.
65  		 */
66  		public Receiver(AsynchronousNotifiable receiver) {
67  			this.receiver = receiver;
68  		}
69  		
70  		/**
71  		 * sets the error-count to zero.
72  		 */
73  		public void clean() {
74  			errors = 0;
75  		}
76  		
77  		/**
78  		 * increases the error-count by one.
79  		 */
80  		public void error() {
81  			errors++;
82  			
83  			if ((NUM_NON_RECHABLE_ALLOWED < errors) && (null == erroneous)) {
84  				erroneous = new LinkedList<Receiver> ();
85  				erroneous.add(this);
86  			}
87  		}
88  		
89  		/**
90  		 * @return the number of errors occurred on this entry.
91  		 */
92  		public int numErrors() {
93  			return errors;
94  		}
95  		
96  		/**
97  		 * @return the receiver of this helper.
98  		 */
99  		public AsynchronousNotifiable getReceiver() {
100 			return receiver;
101 		}
102 	}
103 	
104 	/**
105 	 * add a new receiver to the list.
106 	 * @param entry the new receiver to be stored in the list.
107 	 */
108 	public void add(AsynchronousNotifiable entry) {
109 		synchronized (receivers) {
110 			receivers.add(new Receiver(entry));
111 		}
112 	}
113 	
114 	/**
115 	 * removes a receiver from the list.
116 	 * @param entry the receiver to be removed.
117 	 */
118 	public void remove(AsynchronousNotifiable entry) {
119 		synchronized (receivers) {
120 			Receiver toBeRemoved = null;
121 			for (Receiver r : receivers) {
122 				if (r.getReceiver().equals(entry)) {
123 					toBeRemoved = r;
124 					break;
125 				}
126 			}
127 			if (null != toBeRemoved) {
128 				receivers.remove(toBeRemoved);
129 			}
130 		}
131 	}
132 	
133 	/**
134 	 * @return if true then the list contains erroneous receivers.
135 	 */
136 	private boolean isDirty() {
137 		return (null == erroneous);
138 	}
139 	
140 	/**
141 	 * removes all the erroneous receivers from the list.
142 	 */
143 	private synchronized void cleanup() {	
144 		if (null != erroneous) {
145 			synchronized (erroneous) {	
146 				synchronized(receivers) {
147 					for (Receiver e : erroneous) {
148 						receivers.remove(e);
149 					}
150 					erroneous = null;
151 				}
152 			}			
153 		}
154 	}
155 
156 	/**
157 	 * notify all the receivers with a new message.
158 	 * @param message the LLRP message.
159 	 * @param readerName the reader that delivered the message.
160 	 * @throws RemoteException when there is an RMI exception.
161 	 */
162 	public void notify(byte[] message, String readerName)
163 			throws RemoteException {
164 		
165 		for (Receiver receiver : receivers) {
166 			try {
167 				
168 				receiver.getReceiver().notify(message, readerName);
169 			} catch (RemoteException e) {
170 				receiver.error();
171 			}
172 			receiver.clean();
173 		}
174 		// run the cleanup routine.
175 		if (isDirty()) {
176 			cleanup();
177 		}
178 	}
179 
180 	/**
181 	 * notify all the receivers about an exception in the reader module.
182 	 * @param e the exception.
183 	 * @param readerName the reader that delivered the exception.
184 	 * @throws RemoteException when there is an RMI exception.
185 	 */
186 	public void notifyError(LLRPRuntimeException e, String readerName)
187 			throws RemoteException {
188 	
189 		for (Receiver receiver : receivers) {
190 			try {
191 				receiver.getReceiver().notifyError(e, readerName);
192 			} catch (RemoteException ex) {
193 				receiver.error();
194 			}
195 			receiver.clean();
196 		}
197 		// run the cleanup routine.
198 		if (isDirty()) {
199 			cleanup();
200 		}
201 	}
202 
203 	/**
204 	 * @return a list holding all the registered receivers.
205 	 */
206 	public List<Receiver> getAll() {
207 		return receivers;
208 	}
209 }