View Javadoc

1   package org.lsst.ccs.bus.mock;
2   
3   import org.lsst.ccs.bus.*;
4   import org.lsst.ccs.utilities.dispatch.CommandFor;
5   import org.lsst.ccs.utilities.dispatch.ParallelCommandDispatcher;
6   
7   import java.io.IOException;
8   import java.util.ArrayList;
9   import java.util.Arrays;
10  import java.util.HashMap;
11  import java.util.List;
12  
13  /**
14   */
15  public class MockBusMessagingLayer implements BusMessagingLayer {
16      /**
17       * for each bus keeps a list of registered "agents" (mostly subsystems)
18       */
19      static class BusRegistry {
20          ArrayList<String>[] registry;
21  
22          BusRegistry() {
23              Bus[] buses = Bus.values();
24              registry = new ArrayList[buses.length];
25              for (int ix = 0; ix < registry.length; ix++) {
26                  registry[ix] = new ArrayList<String>();
27              }
28          }
29  
30      }
31  
32      static class AgentBehaviour {
33          ParallelCommandDispatcher[] dispatchers;
34  
35          AgentBehaviour() {
36              Bus[] buses = Bus.values();
37              dispatchers = new ParallelCommandDispatcher[buses.length];
38              // NO only at registration!! change!
39              /*
40              for(int ix = 0 ; ix < dispatchers.length ; ix++) {
41                  dispatchers[ix] = new ParallelCommandDispatcher() ;
42              }
43              */
44          }
45  
46      }
47  
48      private static final HashMap<String, AgentBehaviour> agentMap = new HashMap<String, AgentBehaviour>();
49      private static final BusRegistry busRegistry = new BusRegistry();
50      private volatile boolean isClosed = false;
51      //TODO: in this implementation there is only one Listener per bus: this should be changed
52      private static final BusMembershipListener[] membershipListeners = new BusMembershipListener[Bus.values().length];
53      private static final Object lock = new Object();
54  
55      private boolean single ;
56  
57  
58      public MockBusMessagingLayer() {
59  
60      }
61  
62      public MockBusMessagingLayer(boolean single) {
63          this.single = single ;
64      }
65  
66      @Override
67      public void register(String agentName, Bus... buses) {
68          //TODO: throw exception?
69          // TODO: problem with multiple tests in same JVM
70          //if (isClosed) return;
71          if(isClosed) {isClosed = false ;}
72          // if agent name null or ""
73          if ((agentName == null) || ("".equals(agentName))) {
74              agentName = ANONYMOUS_AGENT;
75          }
76          // if buses is empty
77          if (buses.length == 0) {
78              buses = Bus.values();
79          }
80          synchronized (lock) {
81              AgentBehaviour behaviour = agentMap.get(agentName);
82              if (behaviour == null) {
83                  behaviour = new AgentBehaviour();
84                  agentMap.put(agentName, behaviour);
85              } else { //TODO stupid addition
86                  //behaviour = new AgentBehaviour();
87                  //agentMap.put(agentName, behaviour);
88              }
89              for (Bus bus : buses) {
90                  int index = bus.ordinal();
91                  busRegistry.registry[index].add(agentName);
92                  //TODO: there might be numerous Listeners!
93                  BusMembershipListener listener = membershipListeners[index];
94                  if (listener != null) {
95                      listener.connecting(agentName, "");
96                  }
97                  if (null == behaviour.dispatchers[index]) {
98                      behaviour.dispatchers[index] = new ParallelCommandDispatcher(single);
99                  }
100             }
101         }
102     }
103 
104     @Override
105     public void closeFor(String agentName, Bus... buses) {
106         //TODO: throw exception?
107         if (isClosed) return;
108         //TODO : stupid!
109         //if (!isClosed) return;
110         // if agent name null or ""
111         if ((agentName == null) || ("".equals(agentName))) {
112             agentName = ANONYMOUS_AGENT;
113         }
114         // if buses is empty
115         if (buses.length == 0) {
116             buses = Bus.values();
117         }
118         synchronized (lock) {
119             AgentBehaviour behaviour = agentMap.get(agentName);
120             for (Bus bus : buses) {
121                 int index = bus.ordinal();
122                 busRegistry.registry[index].remove(agentName);
123                 BusMembershipListener listener = membershipListeners[index];
124                 if (listener != null) {
125                     listener.disconnecting(agentName, "");
126                 }
127                 if (behaviour != null) {
128                     behaviour.dispatchers[index] = null;
129                 }
130             }
131         }
132     }
133 
134     @Override
135     public void close() throws IOException {
136         //TODO: change that!
137         isClosed = true;
138     }
139 
140 
141     @Override
142     public synchronized <T extends BusPayload> void sendMessage(String senderAgent, Bus<T> bus, final T message, String... destinations) throws IOException {
143         if (bus == null) throw new IllegalArgumentException("null bus");
144         if (message == null) throw new IllegalArgumentException("null message");
145         synchronized (lock) {
146             // is sendAgent registered for this bus?
147             ArrayList<String> busAgents = busRegistry.registry[bus.ordinal()];
148             if (!busAgents.contains(senderAgent)) {
149                 throw new IllegalArgumentException("agent " + senderAgent + "not registered on " + bus);
150             }
151             if (destinations.length == 0 || "".equals(destinations[0]) || "*".equals(destinations[0])) {
152                 //send to all
153                 int index = bus.ordinal();
154                 destinations = (busRegistry.registry[index]).toArray(destinations);
155             } else { // adds ANONYMOUS_AGENT to destinations
156                 int length = destinations.length;
157                 destinations = Arrays.copyOf(destinations, length + 1);
158                 destinations[length] = ANONYMOUS_AGENT;
159 
160             }
161             CommandFor<BusMessageForwarder> cmdMessage = new CommandFor<BusMessageForwarder>() {
162                 @Override
163                 public void invokeOn(BusMessageForwarder instance) {
164                     instance.update((BusMessage) message);
165                 }
166             };
167 
168             List<String> failed = new ArrayList<String>();
169             for (String destination : destinations) {
170                 AgentBehaviour behaviour = agentMap.get(destination);
171                 if (behaviour == null) {
172                     if (!destination.equals(ANONYMOUS_AGENT)) {
173                         failed.add(destination);
174                     }
175                     continue;
176                     //throw new IllegalArgumentException(destination + " agent with no registration");
177                     //return ;
178                 }
179                 int index = bus.ordinal();
180                 ParallelCommandDispatcher dispatcher = behaviour.dispatchers[index];
181                 if (dispatcher == null) {
182                     // TODO change this!!!
183                     if (!destination.equals(ANONYMOUS_AGENT)) {
184                         failed.add(destination);
185                     }
186                     //throw new IllegalArgumentException(destination + " not registered with " + bus);
187                     //return ;
188                     continue;
189                 }
190                 dispatcher.dispatchCommand(cmdMessage);
191             }
192             if (failed.size() != 0) {
193                 throw new DestinationsException(failed.toArray());
194             }
195         }
196 
197     }
198 
199     @Override
200     public void addMessageListener(String agentName, BusMessageForwarder forwarder, Bus... buses) {
201         if (forwarder == null) throw new IllegalArgumentException("null forwarder");
202         //TODO: throw exception?
203         //TODO: change that!
204         if (isClosed) return;
205         // if agent name null or ""
206         if ((agentName == null) || ("".equals(agentName))) {
207             agentName = ANONYMOUS_AGENT;
208         }
209         // if buses is empty
210         if (buses.length == 0) {
211             buses = Bus.values();
212         }
213         synchronized (lock) {
214             AgentBehaviour behaviour = agentMap.get(agentName);
215             if (behaviour == null) {
216                 throw new IllegalArgumentException("agent with no registration");
217             }
218 
219             for (Bus bus : buses) {
220                 int index = bus.ordinal();
221                 ParallelCommandDispatcher dispatcher = behaviour.dispatchers[index];
222                 if (dispatcher == null) {
223                     throw new IllegalArgumentException(agentName + " not registered with " + bus);
224                 }
225                 dispatcher.addExecutant(forwarder);
226             }
227         }
228 
229     }
230 
231     @Override
232     public void removeMessageListener(String agentName, BusMessageForwarder forwarder, Bus... buses) {
233         if (forwarder == null) throw new IllegalArgumentException("null forwarder");
234         //TODO: throw exception?
235         //TODO: change that
236         if (isClosed) return;
237         // if agent name null or ""
238         if ((agentName == null) || ("".equals(agentName))) {
239             agentName = ANONYMOUS_AGENT;
240         }
241         // if buses is empty
242         if (buses.length == 0) {
243             buses = Bus.values();
244         }
245         synchronized (lock) {
246             AgentBehaviour behaviour = agentMap.get(agentName);
247             if (behaviour == null) {
248                 return;
249             }
250 
251             for (Bus bus : buses) {
252                 int index = bus.ordinal();
253                 ParallelCommandDispatcher dispatcher = behaviour.dispatchers[index];
254                 if (dispatcher == null) {
255                     return;
256                 }
257                 dispatcher.removeExecutant(forwarder);
258             }
259         }
260     }
261 
262     @Override
263     public void setMembershipListener(BusMembershipListener listener, Bus... buses) {
264         if (buses == null || buses.length == 0) {
265             buses = Bus.values();
266         }
267         synchronized (lock) {
268             for (Bus bus : buses) {
269                 membershipListeners[bus.ordinal()] = listener;
270             }
271         }
272     }
273 
274     @Override
275     public List<String> getConnectedNames(Bus bus) {
276         int index = bus.ordinal();
277         return busRegistry.registry[index];
278     }
279 }