1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.asteriskjava.manager.internal;
18
19 import org.asteriskjava.manager.event.DisconnectEvent;
20 import org.asteriskjava.manager.event.ManagerEvent;
21 import org.asteriskjava.manager.event.ProtocolIdentifierReceivedEvent;
22 import org.asteriskjava.manager.response.CommandResponse;
23 import org.asteriskjava.manager.response.ManagerResponse;
24 import org.asteriskjava.util.DateUtil;
25 import org.asteriskjava.util.Log;
26 import org.asteriskjava.util.LogFactory;
27 import org.asteriskjava.util.SocketConnectionFacade;
28
29 import java.io.IOException;
30 import java.util.*;
31
32
33 /***
34 * Default implementation of the ManagerReader interface.
35 *
36 * @author srt
37 * @version $Id: ManagerReaderImpl.java 878 2007-08-01 22:04:11Z srt $
38 */
39 public class ManagerReaderImpl implements ManagerReader
40 {
41 /***
42 * Instance logger.
43 */
44 private final Log logger = LogFactory.getLog(getClass());
45
46 /***
47 * The event builder utility to convert a map of attributes reveived from asterisk to instances
48 * of registered event classes.
49 */
50 private final EventBuilder eventBuilder;
51
52 /***
53 * The response builder utility to convert a map of attributes reveived from asterisk to
54 * instances of well known response classes.
55 */
56 private final ResponseBuilder responseBuilder;
57
58 /***
59 * The dispatcher to use for dispatching events and responses.
60 */
61 private final Dispatcher dispatcher;
62
63 /***
64 * The source to use when creating {@link ManagerEvent}s.
65 */
66 private final Object source;
67
68 /***
69 * The socket to use for reading from the asterisk server.
70 */
71 private SocketConnectionFacade socket;
72
73 /***
74 * If set to <code>true</code>, terminates and closes the reader.
75 */
76 private boolean die = false;
77
78 /***
79 * <code>true</code> if the main loop has finished.
80 */
81 private boolean dead = false;
82
83 /***
84 * Exception that caused this reader to terminate if any.
85 */
86 private IOException terminationException;
87
88 /***
89 * Creates a new ManagerReaderImpl.
90 *
91 * @param dispatcher the dispatcher to use for dispatching events and responses.
92 * @param source the source to use when creating {@link ManagerEvent}s
93 */
94 public ManagerReaderImpl(final Dispatcher dispatcher, Object source)
95 {
96 this.dispatcher = dispatcher;
97 this.source = source;
98
99 this.eventBuilder = new EventBuilderImpl();
100 this.responseBuilder = new ResponseBuilderImpl();
101 }
102
103 /***
104 * Sets the socket to use for reading from the asterisk server.
105 *
106 * @param socket the socket to use for reading from the asterisk server.
107 */
108 public void setSocket(final SocketConnectionFacade socket)
109 {
110 this.socket = socket;
111 }
112
113 public void registerEventClass(Class eventClass)
114 {
115 eventBuilder.registerEventClass(eventClass);
116 }
117
118 /***
119 * Reads line by line from the asterisk server, sets the protocol identifier (using a
120 * generated {@link org.asteriskjava.manager.event.ProtocolIdentifierReceivedEvent}) as soon as it is
121 * received and dispatches the received events and responses via the associated dispatcher.
122 *
123 * @see org.asteriskjava.manager.internal.Dispatcher#dispatchEvent(ManagerEvent)
124 * @see org.asteriskjava.manager.internal.Dispatcher#dispatchResponse(ManagerResponse)
125 */
126 public void run()
127 {
128 final Map<String, String> buffer = new HashMap<String, String>();
129 final List<String> commandResult = new ArrayList<String>();
130 String line;
131 boolean processingCommandResult = false;
132
133 if (socket == null)
134 {
135 throw new IllegalStateException("Unable to run: socket is null.");
136 }
137
138 this.die = false;
139 this.dead = false;
140
141 try
142 {
143
144 while ((line = socket.readLine()) != null && !this.die)
145 {
146
147
148 if (processingCommandResult)
149 {
150
151
152 if ("--END COMMAND--".equals(line) || " --END COMMAND--".equals(line))
153 {
154 CommandResponse commandResponse = new CommandResponse();
155
156 for (int crIdx = 0; crIdx < commandResult.size(); crIdx++)
157 {
158 String[] crNVPair = commandResult.get(crIdx).split(" *: *", 2);
159
160 if (crNVPair[0].equalsIgnoreCase("ActionID"))
161 {
162
163
164
165 commandResult.remove(crIdx--);
166
167
168 commandResponse.setActionId(crNVPair[1]);
169 }
170 else if (crNVPair[0].equalsIgnoreCase("Privilege"))
171 {
172
173
174
175 commandResult.remove(crIdx--);
176 }
177 else
178 {
179
180
181 break;
182 }
183 }
184 commandResponse.setResponse("Follows");
185 commandResponse.setDateReceived(DateUtil.getDate());
186
187 commandResponse.setResult(new ArrayList<String>(commandResult));
188 Map<String, String> attributes = new HashMap<String, String>();
189 attributes.put("actionid", commandResponse.getActionId());
190 attributes.put("response", commandResponse.getResponse());
191 commandResponse.setAttributes(attributes);
192 dispatcher.dispatchResponse(commandResponse);
193 processingCommandResult = false;
194 }
195 else
196 {
197 commandResult.add(line);
198 }
199 continue;
200 }
201
202
203
204
205 if ("Response: Follows".equalsIgnoreCase(line))
206 {
207 processingCommandResult = true;
208 commandResult.clear();
209 continue;
210 }
211
212
213
214 if (line.startsWith("Asterisk Call Manager/") ||
215 line.startsWith("Asterisk Call Manager Proxy/") ||
216 line.startsWith("OpenPBX Call Manager/") ||
217 line.startsWith("CallWeaver Call Manager/"))
218 {
219 ProtocolIdentifierReceivedEvent protocolIdentifierReceivedEvent;
220 protocolIdentifierReceivedEvent = new ProtocolIdentifierReceivedEvent(source);
221 protocolIdentifierReceivedEvent.setProtocolIdentifier(line);
222 protocolIdentifierReceivedEvent.setDateReceived(DateUtil.getDate());
223 dispatcher.dispatchEvent(protocolIdentifierReceivedEvent);
224 continue;
225 }
226
227
228
229 if (line.length() == 0)
230 {
231 if (buffer.containsKey("event"))
232 {
233
234
235 ManagerEvent event = buildEvent(source, buffer);
236 if (event != null)
237 {
238 dispatcher.dispatchEvent(event);
239 }
240 else
241 {
242 logger.debug("buildEvent returned null");
243 }
244 }
245 else if (buffer.containsKey("response"))
246 {
247 ManagerResponse response = buildResponse(buffer);
248
249
250 if (response != null)
251 {
252 dispatcher.dispatchResponse(response);
253 }
254 }
255 else
256 {
257 if (buffer.size() > 0)
258 {
259 logger.debug("buffer contains neither response nor event");
260 }
261 }
262
263 buffer.clear();
264 }
265 else
266 {
267 int delimiterIndex;
268
269 delimiterIndex = line.indexOf(":");
270 if (delimiterIndex > 0 && line.length() > delimiterIndex + 2)
271 {
272 String name;
273 String value;
274
275 name = line.substring(0, delimiterIndex).toLowerCase(Locale.ENGLISH);
276 value = line.substring(delimiterIndex + 2);
277
278 buffer.put(name, value);
279
280
281 }
282 }
283 }
284 this.dead = true;
285 logger.debug("Reached end of stream, terminating reader.");
286 }
287 catch (IOException e)
288 {
289 this.terminationException = e;
290 this.dead = true;
291 logger.info("Terminating reader thread: " + e.getMessage());
292 }
293 finally
294 {
295 this.dead = true;
296
297 DisconnectEvent disconnectEvent = new DisconnectEvent(source);
298 disconnectEvent.setDateReceived(DateUtil.getDate());
299 dispatcher.dispatchEvent(disconnectEvent);
300 }
301 }
302
303 public void die()
304 {
305 this.die = true;
306 }
307
308 public boolean isDead()
309 {
310 return dead;
311 }
312
313 public IOException getTerminationException()
314 {
315 return terminationException;
316 }
317
318 private ManagerResponse buildResponse(Map<String, String> buffer)
319 {
320 ManagerResponse response;
321
322 response = responseBuilder.buildResponse(buffer);
323
324 if (response != null)
325 {
326 response.setDateReceived(DateUtil.getDate());
327 }
328
329 return response;
330 }
331
332 private ManagerEvent buildEvent(Object source, Map<String, String> buffer)
333 {
334 ManagerEvent event;
335
336 event = eventBuilder.buildEvent(source, buffer);
337
338 if (event != null)
339 {
340 event.setDateReceived(DateUtil.getDate());
341 }
342
343 return event;
344 }
345 }