View Javadoc

1   /*
2    *  Copyright 2004-2006 Stefan Reuter
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *
16   */
17  package org.asteriskjava.live.internal;
18  
19  import org.asteriskjava.live.*;
20  import org.asteriskjava.manager.ResponseEvents;
21  import org.asteriskjava.manager.action.StatusAction;
22  import org.asteriskjava.manager.event.*;
23  import org.asteriskjava.util.DateUtil;
24  import org.asteriskjava.util.Log;
25  import org.asteriskjava.util.LogFactory;
26  
27  import java.util.*;
28  
29  /**
30   * Manages channel events on behalf of an AsteriskServer.
31   *
32   * @author srt
33   * @version $Id$
34   */
35  class ChannelManager
36  {
37      private final Log logger = LogFactory.getLog(getClass());
38  
39      /**
40       * How long we wait before we remove hung up channels from memory (in milliseconds).
41       */
42      private static final long REMOVAL_THRESHOLD = 15 * 60 * 1000L; // 15 minutes
43      private static final long SLEEP_TIME_BEFORE_GET_VAR = 50L;
44  
45      private final AsteriskServerImpl server;
46  
47      /**
48       * A map of all active channel by their unique id.
49       */
50      private final Set<AsteriskChannelImpl> channels;
51  
52      /**
53       * Creates a new instance.
54       *
55       * @param server the server this channel manager belongs to.
56       */
57      ChannelManager(AsteriskServerImpl server)
58      {
59          this.server = server;
60          this.channels = new HashSet<AsteriskChannelImpl>();
61      }
62  
63      void initialize() throws ManagerCommunicationException
64      {
65          initialize(null);
66      }
67  
68      void initialize(List<String> variables) throws ManagerCommunicationException
69      {
70          ResponseEvents re;
71  
72          disconnected();
73          StatusAction sa = new StatusAction();
74          sa.setVariables(variables);
75          re = server.sendEventGeneratingAction(sa);
76          for (ManagerEvent event : re.getEvents())
77          {
78              if (event instanceof StatusEvent)
79              {
80                  handleStatusEvent((StatusEvent) event);
81              }
82          }
83      }
84  
85      void disconnected()
86      {
87          synchronized (channels)
88          {
89              channels.clear();
90          }
91      }
92  
93      /**
94       * Returns a collection of all active AsteriskChannels.
95       *
96       * @return a collection of all active AsteriskChannels.
97       */
98      Collection<AsteriskChannel> getChannels()
99      {
100         Collection<AsteriskChannel> copy;
101 
102         synchronized (channels)
103         {
104             copy = new ArrayList<AsteriskChannel>(channels.size() + 2);
105             for (AsteriskChannel channel : channels)
106             {
107                 if (channel.getState() != ChannelState.HUNGUP)
108                 {
109                     copy.add(channel);
110                 }
111             }
112         }
113         return copy;
114     }
115 
116     private void addChannel(AsteriskChannelImpl channel)
117     {
118         synchronized (channels)
119         {
120             channels.add(channel);
121         }
122     }
123 
124     /**
125      * Removes channels that have been hung more than {@link #REMOVAL_THRESHOLD} milliseconds.
126      */
127     private void removeOldChannels()
128     {
129         Iterator<AsteriskChannelImpl> i;
130 
131         synchronized (channels)
132         {
133             i = channels.iterator();
134             while (i.hasNext())
135             {
136                 final AsteriskChannel channel = i.next();
137                 final Date dateOfRemoval = channel.getDateOfRemoval();
138                 if (channel.getState() == ChannelState.HUNGUP && dateOfRemoval != null)
139                 {
140                     final long diff = DateUtil.getDate().getTime() - dateOfRemoval.getTime();
141                     if (diff >= REMOVAL_THRESHOLD)
142                     {
143                         i.remove();
144                     }
145                 }
146             }
147         }
148     }
149 
150     private AsteriskChannelImpl addNewChannel(String uniqueId, String name,
151                                               Date dateOfCreation, String callerIdNumber, String callerIdName,
152                                               ChannelState state, String account)
153     {
154         final AsteriskChannelImpl channel;
155         final String traceId;
156 
157         channel = new AsteriskChannelImpl(server, name, uniqueId, dateOfCreation);
158         channel.setCallerId(new CallerId(callerIdName, callerIdNumber));
159         channel.setAccount(account);
160         channel.stateChanged(dateOfCreation, state);
161         logger.info("Adding channel " + channel.getName() + "(" + channel.getId() + ")");
162 
163         if (SLEEP_TIME_BEFORE_GET_VAR > 0)
164         {
165             try
166             {
167                 Thread.sleep(SLEEP_TIME_BEFORE_GET_VAR);
168             }
169             catch (InterruptedException e)
170             {
171                 Thread.currentThread().interrupt();
172             }
173         }
174 
175         traceId = getTraceId(channel);
176         channel.setTraceId(traceId);
177 
178         addChannel(channel);
179 
180         if (traceId != null && (!name.toLowerCase(Locale.ENGLISH).startsWith("local/") || (name.endsWith(",1") || name.endsWith(";1"))))
181         {
182             final OriginateCallbackData callbackData;
183             callbackData = server.getOriginateCallbackDataByTraceId(traceId);
184             if (callbackData != null && callbackData.getChannel() == null)
185             {
186                 callbackData.setChannel(channel);
187                 try
188                 {
189                     callbackData.getCallback().onDialing(channel);
190                 }
191                 catch (Throwable t)
192                 {
193                     logger.warn("Exception dispatching originate progress.", t);
194                 }
195             }
196         }
197         server.fireNewAsteriskChannel(channel);
198         return channel;
199     }
200 
201     void handleStatusEvent(StatusEvent event)
202     {
203         AsteriskChannelImpl channel;
204         final Extension extension;
205         boolean isNew = false;
206         Map<String, String> variables = event.getVariables();
207 
208         channel = getChannelImplById(event.getUniqueId());
209         if (channel == null)
210         {
211             Date dateOfCreation;
212 
213             if (event.getSeconds() != null)
214             {
215                 dateOfCreation = new Date(DateUtil.getDate().getTime() - (event.getSeconds() * 1000L));
216             }
217             else
218             {
219                 dateOfCreation = DateUtil.getDate();
220             }
221             channel = new AsteriskChannelImpl(server, event.getChannel(), event.getUniqueId(), dateOfCreation);
222             isNew = true;
223             if (variables != null)
224             {
225                 for (String variable : variables.keySet())
226                 {
227                     channel.updateVariable(variable, variables.get(variable));
228                 }
229             }
230         }
231 
232         if (event.getContext() == null && event.getExtension() == null
233                 && event.getPriority() == null)
234         {
235             extension = null;
236         }
237         else
238         {
239             extension = new Extension(event.getContext(), event.getExtension(), event.getPriority());
240         }
241 
242         synchronized (channel)
243         {
244             channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
245             channel.setAccount(event.getAccountCode());
246             if (event.getChannelState() != null)
247             {
248                 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
249             }
250             channel.extensionVisited(event.getDateReceived(), extension);
251 
252             if (event.getBridgedChannel() != null)
253             {
254                 final AsteriskChannelImpl linkedChannel = getChannelImplByName(event.getBridgedChannel());
255                 if (linkedChannel != null)
256                 {
257                     // the date used here is not correct!
258                     channel.channelLinked(event.getDateReceived(), linkedChannel);
259                     synchronized (linkedChannel)
260                     {
261                         linkedChannel.channelLinked(event.getDateReceived(), channel);
262                     }
263                 }
264             }
265         }
266 
267         if (isNew)
268         {
269             logger.info("Adding new channel " + channel.getName());
270             addChannel(channel);
271             server.fireNewAsteriskChannel(channel);
272         }
273     }
274 
275     /**
276      * Returns a channel from the ChannelManager's cache with the given name
277      * If multiple channels are found, returns the most recently CREATED one.
278      * If two channels with the very same date exist, avoid HUNGUP ones.
279      *
280      * @param name the name of the requested channel.
281      * @return the (most recent) channel if found, in any state, or null if none found.
282      */
283     AsteriskChannelImpl getChannelImplByName(String name)
284     {
285         Date dateOfCreation = null;
286         AsteriskChannelImpl channel = null;
287 
288         if (name == null)
289         {
290             return null;
291         }
292 
293         synchronized (channels)
294         {
295             for (AsteriskChannelImpl tmp : channels)
296             {
297                 if (tmp.getName() != null && tmp.getName().equals(name))
298                 {
299                     // return the most recent channel or when dates are similar, the active one
300                     if (dateOfCreation == null ||
301                             tmp.getDateOfCreation().after(dateOfCreation) ||
302                             (tmp.getDateOfCreation().equals(dateOfCreation) && tmp.getState() != ChannelState.HUNGUP))
303                     {
304                         channel = tmp;
305                         dateOfCreation = channel.getDateOfCreation();
306                     }
307                 }
308             }
309         }
310         return channel;
311     }
312 
313     /**
314      * Returns a NON-HUNGUP channel from the ChannelManager's cache with the given name.
315      *
316      * @param name the name of the requested channel.
317      * @return the NON-HUNGUP channel if found, or null if none is found.
318      */
319     AsteriskChannelImpl getChannelImplByNameAndActive(String name)
320     {
321 
322         // In non bristuffed AST 1.2, we don't have uniqueid header to match the channel
323         // So we must use the channel name
324         // Channel name is unique at any give moment in the  * server
325         // But asterisk-java keeps Hungup channels for a while.
326         // We don't want to retrieve hungup channels.
327 
328         AsteriskChannelImpl channel = null;
329 
330         if (name == null)
331         {
332             return null;
333         }
334 
335         synchronized (channels)
336         {
337             for (AsteriskChannelImpl tmp : channels)
338             {
339                 if (tmp.getName() != null && tmp.getName().equals(name) && tmp.getState() != ChannelState.HUNGUP)
340                 {
341                     channel = tmp;
342                 }
343             }
344         }
345         return channel;
346     }
347 
348     AsteriskChannelImpl getChannelImplById(String id)
349     {
350         if (id == null)
351         {
352             return null;
353         }
354 
355         synchronized (channels)
356         {
357             for (AsteriskChannelImpl channel : channels)
358             {
359                 if (id.equals(channel.getId()))
360                 {
361                     return channel;
362                 }
363             }
364         }
365         return null;
366     }
367 
368     /**
369      * Returns the other side of a local channel.
370      * <p/>
371      * Local channels consist of two sides, like
372      * "Local/1234@from-local-60b5,1" and "Local/1234@from-local-60b5,2" (for Asterisk 1.4) or
373      * "Local/1234@from-local-60b5;1" and "Local/1234@from-local-60b5;2" (for Asterisk 1.6)
374      * this method returns the other side.
375      *
376      * @param localChannel one side
377      * @return the other side, or <code>null</code> if not available or if the given channel
378      *         is not a local channel.
379      */
380     AsteriskChannelImpl getOtherSideOfLocalChannel(AsteriskChannel localChannel)
381     {
382         final String name;
383         final char num;
384 
385         if (localChannel == null)
386         {
387             return null;
388         }
389 
390         name = localChannel.getName();
391         if (name == null || !name.startsWith("Local/") || (name.charAt(name.length() - 2) != ',' && name.charAt(name.length() - 2) != ';'))
392         {
393             return null;
394         }
395 
396         num = name.charAt(name.length() - 1);
397 
398         if (num == '1')
399         {
400             return getChannelImplByName(name.substring(0, name.length() - 1) + "2");
401         }
402         else if (num == '2')
403         {
404             return getChannelImplByName(name.substring(0, name.length() - 1) + "1");
405         }
406         else
407         {
408             return null;
409         }
410     }
411 
412     void handleNewChannelEvent(NewChannelEvent event)
413     {
414         final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
415 
416         if (channel == null)
417         {
418             if (event.getChannel() == null)
419             {
420                 logger.info("Ignored NewChannelEvent with empty channel name (uniqueId=" + event.getUniqueId() + ")");
421             }
422             else
423             {
424                 addNewChannel(
425                         event.getUniqueId(), event.getChannel(), event.getDateReceived(),
426                         event.getCallerIdNum(), event.getCallerIdName(),
427                         ChannelState.valueOf(event.getChannelState()), event.getAccountCode());
428             }
429         }
430         else
431         {
432             // channel had already been created probably by a NewCallerIdEvent
433             synchronized (channel)
434             {
435                 channel.nameChanged(event.getDateReceived(), event.getChannel());
436                 channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
437                 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
438             }
439         }
440     }
441 
442     void handleNewExtenEvent(NewExtenEvent event)
443     {
444         AsteriskChannelImpl channel;
445         final Extension extension;
446 
447         channel = getChannelImplById(event.getUniqueId());
448         if (channel == null)
449         {
450             logger.error("Ignored NewExtenEvent for unknown channel " + event.getChannel());
451             return;
452         }
453 
454         extension = new Extension(
455                 event.getContext(), event.getExtension(), event.getPriority(),
456                 event.getApplication(), event.getAppData());
457 
458         synchronized (channel)
459         {
460             channel.extensionVisited(event.getDateReceived(), extension);
461         }
462     }
463 
464     void handleNewStateEvent(NewStateEvent event)
465     {
466         AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
467 
468         if (channel == null)
469         {
470             // NewStateEvent can occur for an existing channel that now has a different unique id (originate with Local/)
471             channel = getChannelImplByNameAndActive(event.getChannel());
472             if (channel != null)
473             {
474                 logger.info("Changing unique id for '" + channel.getName() + "' from " + channel.getId() + " to " + event.getUniqueId());
475                 channel.idChanged(event.getDateReceived(), event.getUniqueId());
476             }
477 
478             if (channel == null)
479             {
480                 logger.info("Creating new channel due to NewStateEvent '" + event.getChannel() + "' unique id " + event.getUniqueId());
481                 // NewStateEvent can occur instead of a NewChannelEvent
482                 channel = addNewChannel(
483                         event.getUniqueId(), event.getChannel(), event.getDateReceived(),
484                         event.getCallerIdNum(), event.getCallerIdName(),
485                         ChannelState.valueOf(event.getChannelState()), null /* account code not available */);
486             }
487         }
488 
489         // NewStateEvent can provide a new CallerIdNum or CallerIdName not previously received through a
490         // NewCallerIdEvent. This happens at least on outgoing legs from the queue application to agents.
491         if (event.getCallerIdNum() != null || event.getCallerIdName() != null)
492         {
493             String cidnum = "";
494             String cidname = "";
495             CallerId currentCallerId = channel.getCallerId();
496 
497             if (currentCallerId != null)
498             {
499                 cidnum = currentCallerId.getNumber();
500                 cidname = currentCallerId.getName();
501             }
502 
503             if (event.getCallerIdNum() != null)
504             {
505                 cidnum = event.getCallerIdNum();
506             }
507 
508             if (event.getCallerIdName() != null)
509             {
510                 cidname = event.getCallerIdName();
511             }
512 
513             CallerId newCallerId = new CallerId(cidname, cidnum);
514             logger.debug("Updating CallerId (following NewStateEvent) to: " + newCallerId.toString());
515             channel.setCallerId(newCallerId);
516 
517             // Also, NewStateEvent can return a new channel name for the same channel uniqueid, indicating the channel has been
518             // renamed but no related RenameEvent has been received.
519             // This happens with mISDN channels (see AJ-153)
520             if (event.getChannel() != null && !event.getChannel().equals(channel.getName()))
521             {
522                 logger.info("Renaming channel (following NewStateEvent) '" + channel.getName() + "' to '" + event.getChannel() + "'");
523                 synchronized (channel)
524                 {
525                     channel.nameChanged(event.getDateReceived(), event.getChannel());
526                 }
527             }
528         }
529 
530         if (event.getChannelState() != null)
531         {
532             synchronized (channel)
533             {
534                 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
535             }
536         }
537     }
538 
539     void handleNewCallerIdEvent(NewCallerIdEvent event)
540     {
541         AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
542 
543         if (channel == null)
544         {
545             // NewCallerIdEvent can occur for an existing channel that now has a different unique id (originate with Local/)
546             channel = getChannelImplByNameAndActive(event.getChannel());
547             if (channel != null)
548             {
549                 logger.info("Changing unique id for '" + channel.getName() + "' from " + channel.getId() + " to " + event.getUniqueId());
550                 channel.idChanged(event.getDateReceived(), event.getUniqueId());
551             }
552 
553             if (channel == null)
554             {
555                 // NewCallerIdEvent can occur before NewChannelEvent
556                 channel = addNewChannel(
557                         event.getUniqueId(), event.getChannel(), event.getDateReceived(),
558                         event.getCallerIdNum(), event.getCallerIdName(),
559                         ChannelState.DOWN, null /* account code not available */);
560             }
561         }
562 
563         synchronized (channel)
564         {
565             channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
566         }
567     }
568 
569     void handleHangupEvent(HangupEvent event)
570     {
571         HangupCause cause = null;
572         AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
573 
574         if (channel == null)
575         {
576             logger.error("Ignored HangupEvent for unknown channel " + event.getChannel());
577             return;
578         }
579 
580         if (event.getCause() != null)
581         {
582             cause = HangupCause.getByCode(event.getCause());
583         }
584 
585         synchronized (channel)
586         {
587             channel.hungup(event.getDateReceived(), cause, event.getCauseTxt());
588         }
589 
590         logger.info("Removing channel " + channel.getName() + " due to hangup (" + cause + ")");
591         removeOldChannels();
592     }
593 
594     void handleDialEvent(DialEvent event)
595     {
596         final AsteriskChannelImpl sourceChannel = getChannelImplById(event.getUniqueId());
597         final AsteriskChannelImpl destinationChannel = getChannelImplById(event.getDestUniqueId());
598 
599         if (sourceChannel == null)
600         {
601             logger.error("Ignored DialEvent for unknown source channel " + event.getChannel() + " with unique id " + event.getUniqueId());
602             return;
603         }
604         if (destinationChannel == null)
605         {
606             logger.error("Ignored DialEvent for unknown destination channel " + event.getDestination() + " with unique id " + event.getDestUniqueId());
607             return;
608         }
609 
610         logger.info(sourceChannel.getName() + " dialed " + destinationChannel.getName());
611         getTraceId(sourceChannel);
612         getTraceId(destinationChannel);
613         synchronized (sourceChannel)
614         {
615             sourceChannel.channelDialed(event.getDateReceived(), destinationChannel);
616         }
617         synchronized (destinationChannel)
618         {
619             destinationChannel.channelDialing(event.getDateReceived(), sourceChannel);
620         }
621     }
622 
623     void handleBridgeEvent(BridgeEvent event)
624     {
625         final AsteriskChannelImpl channel1 = getChannelImplById(event.getUniqueId1());
626         final AsteriskChannelImpl channel2 = getChannelImplById(event.getUniqueId2());
627 
628         if (channel1 == null)
629         {
630             logger.error("Ignored BridgeEvent for unknown channel " + event.getChannel1());
631             return;
632         }
633         if (channel2 == null)
634         {
635             logger.error("Ignored BridgeEvent for unknown channel " + event.getChannel2());
636             return;
637         }
638 
639         if (event.isLink())
640         {
641             logger.info("Linking channels " + channel1.getName() + " and " + channel2.getName());
642             synchronized (channel1)
643             {
644                 channel1.channelLinked(event.getDateReceived(), channel2);
645             }
646 
647             synchronized (channel2)
648             {
649                 channel2.channelLinked(event.getDateReceived(), channel1);
650             }
651         }
652 
653         if (event.isUnlink())
654         {
655             logger.info("Unlinking channels " + channel1.getName() + " and " + channel2.getName());
656             synchronized (channel1)
657             {
658                 channel1.channelUnlinked(event.getDateReceived());
659             }
660 
661             synchronized (channel2)
662             {
663                 channel2.channelUnlinked(event.getDateReceived());
664             }
665         }
666     }
667 
668     void handleRenameEvent(RenameEvent event)
669     {
670         AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
671 
672         if (channel == null)
673         {
674             logger.error("Ignored RenameEvent for unknown channel with uniqueId " + event.getUniqueId());
675             return;
676         }
677 
678         logger.info("Renaming channel '" + channel.getName() + "' to '" + event.getNewname() + "', uniqueId is " + event.getUniqueId());
679         synchronized (channel)
680         {
681             channel.nameChanged(event.getDateReceived(), event.getNewname());
682         }
683     }
684 
685     void handleCdrEvent(CdrEvent event)
686     {
687         final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
688         final AsteriskChannelImpl destinationChannel = getChannelImplByName(event.getDestinationChannel());
689         final CallDetailRecordImpl cdr;
690 
691         if (channel == null)
692         {
693             logger.info("Ignored CdrEvent for unknown channel with uniqueId " + event.getUniqueId());
694             return;
695         }
696 
697         cdr = new CallDetailRecordImpl(channel, destinationChannel, event);
698 
699         synchronized (channel)
700         {
701             channel.callDetailRecordReceived(event.getDateReceived(), cdr);
702         }
703     }
704 
705     private String getTraceId(AsteriskChannel channel)
706     {
707         String traceId;
708 
709         try
710         {
711             traceId = channel.getVariable(Constants.VARIABLE_TRACE_ID);
712         }
713         catch (Exception e)
714         {
715             traceId = null;
716         }
717         //logger.info("TraceId for channel " + channel.getName() + " is " + traceId);
718         return traceId;
719     }
720 
721     void handleParkedCallEvent(ParkedCallEvent event)
722     {
723         // Only bristuffed versions: AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
724         AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
725 
726         if (channel == null)
727         {
728             logger.info("Ignored ParkedCallEvent for unknown channel "
729                     + event.getChannel());
730             return;
731         }
732 
733         synchronized (channel)
734         {
735             // todo The context should be "parkedcalls" or whatever has been configured in features.conf
736             // unfortunately we don't get the context in the ParkedCallEvent so for now we'll set it to null.
737             Extension ext = new Extension(null, event.getExten(), 1);
738             channel.setParkedAt(ext);
739             logger.info("Channel " + channel.getName() + " is parked at " + channel.getParkedAt().getExtension());
740         }
741     }
742 
743     void handleParkedCallGiveUpEvent(ParkedCallGiveUpEvent event)
744     {
745         // Only bristuffed versions: AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
746         AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
747 
748         if (channel == null)
749         {
750             logger.info("Ignored ParkedCallGiveUpEvent for unknown channel "
751                     + event.getChannel());
752             return;
753         }
754 
755         Extension wasParkedAt = channel.getParkedAt();
756 
757         if (wasParkedAt == null)
758         {
759             logger.info("Ignored ParkedCallGiveUpEvent as the channel was not parked");
760             return;
761         }
762 
763         synchronized (channel)
764         {
765             channel.setParkedAt(null);
766         }
767         logger.info("Channel " + channel.getName() + " is unparked (GiveUp) from " + wasParkedAt.getExtension());
768     }
769 
770     void handleParkedCallTimeOutEvent(ParkedCallTimeOutEvent event)
771     {
772         // Only bristuffed versions: AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
773         final AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
774 
775         if (channel == null)
776         {
777             logger.info("Ignored ParkedCallTimeOutEvent for unknown channel " + event.getChannel());
778             return;
779         }
780 
781         Extension wasParkedAt = channel.getParkedAt();
782 
783         if (wasParkedAt == null)
784         {
785             logger.info("Ignored ParkedCallTimeOutEvent as the channel was not parked");
786             return;
787         }
788 
789         synchronized (channel)
790         {
791             channel.setParkedAt(null);
792         }
793         logger.info("Channel " + channel.getName() + " is unparked (Timeout) from " + wasParkedAt.getExtension());
794     }
795 
796     void handleUnparkedCallEvent(UnparkedCallEvent event)
797     {
798         // Only bristuffed versions: AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
799         final AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
800 
801         if (channel == null)
802         {
803             logger.info("Ignored UnparkedCallEvent for unknown channel " + event.getChannel());
804             return;
805         }
806 
807         Extension wasParkedAt = channel.getParkedAt();
808 
809         if (wasParkedAt == null)
810         {
811             logger.info("Ignored UnparkedCallEvent as the channel was not parked");
812             return;
813         }
814 
815         synchronized (channel)
816         {
817             channel.setParkedAt(null);
818         }
819         logger.info("Channel " + channel.getName() + " is unparked (moved away) from " + wasParkedAt.getExtension());
820     }
821 
822     void handleVarSetEvent(VarSetEvent event)
823     {
824         if (event.getUniqueId() == null)
825         {
826             return;
827         }
828 
829         final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
830         if (channel == null)
831         {
832             logger.info("Ignored VarSetEvent for unknown channel with uniqueId " + event.getUniqueId());
833             return;
834         }
835 
836         synchronized (channel)
837         {
838             channel.updateVariable(event.getVariable(), event.getValue());
839         }
840     }
841 
842     void handleDtmfEvent(DtmfEvent event)
843     {
844         // we are only intrested in END events
845         if (event.isBegin())
846         {
847             return;
848         }
849 
850         if (event.getUniqueId() == null)
851         {
852             return;
853         }
854 
855         final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
856         if (channel == null)
857         {
858             logger.info("Ignored DtmfEvent for unknown channel with uniqueId " + event.getUniqueId());
859             return;
860         }
861 
862         final Character dtmfDigit;
863         if (event.getDigit() == null || event.getDigit().length() < 1)
864         {
865             dtmfDigit = null;
866         }
867         else
868         {
869             dtmfDigit = event.getDigit().charAt(0);
870         }
871 
872         synchronized (channel)
873         {
874             if (event.isReceived())
875             {
876                 channel.dtmfReceived(dtmfDigit);
877             }
878             if (event.isSent())
879             {
880                 channel.dtmfSent(dtmfDigit);
881             }
882         }
883     }
884 }