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 }