All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.asteriskjava.live.internal.AsteriskServerImpl Maven / Gradle / Ivy

There is a newer version: 3.41.0
Show newest version
/*
 *  Copyright 2004-2006 Stefan Reuter
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.asteriskjava.live.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.asteriskjava.AsteriskVersion;
import org.asteriskjava.config.ConfigFile;
import org.asteriskjava.live.AsteriskAgent;
import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.AsteriskQueue;
import org.asteriskjava.live.AsteriskQueueEntry;
import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.AsteriskServerListener;
import org.asteriskjava.live.CallerId;
import org.asteriskjava.live.ChannelState;
import org.asteriskjava.live.LiveException;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.live.MeetMeRoom;
import org.asteriskjava.live.MeetMeUser;
import org.asteriskjava.live.NoSuchChannelException;
import org.asteriskjava.live.OriginateCallback;
import org.asteriskjava.live.Voicemailbox;
import org.asteriskjava.lock.Lockable;
import org.asteriskjava.lock.LockableList;
import org.asteriskjava.lock.LockableMap;
import org.asteriskjava.lock.LockableSet;
import org.asteriskjava.lock.Locker.LockCloser;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerConnectionState;
import org.asteriskjava.manager.ManagerEventListener;
import org.asteriskjava.manager.ManagerEventListenerProxy;
import org.asteriskjava.manager.ResponseEvents;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.action.DbGetAction;
import org.asteriskjava.manager.action.DbPutAction;
import org.asteriskjava.manager.action.EventGeneratingAction;
import org.asteriskjava.manager.action.GetConfigAction;
import org.asteriskjava.manager.action.GetVarAction;
import org.asteriskjava.manager.action.MailboxCountAction;
import org.asteriskjava.manager.action.ManagerAction;
import org.asteriskjava.manager.action.ModuleCheckAction;
import org.asteriskjava.manager.action.ModuleLoadAction;
import org.asteriskjava.manager.action.OriginateAction;
import org.asteriskjava.manager.action.SetVarAction;
import org.asteriskjava.manager.action.SipPeersAction;
import org.asteriskjava.manager.event.AbstractMeetMeEvent;
import org.asteriskjava.manager.event.AgentCallbackLoginEvent;
import org.asteriskjava.manager.event.AgentCallbackLogoffEvent;
import org.asteriskjava.manager.event.AgentCalledEvent;
import org.asteriskjava.manager.event.AgentCompleteEvent;
import org.asteriskjava.manager.event.AgentConnectEvent;
import org.asteriskjava.manager.event.AgentLoginEvent;
import org.asteriskjava.manager.event.AgentLogoffEvent;
import org.asteriskjava.manager.event.AgentsEvent;
import org.asteriskjava.manager.event.BridgeEvent;
import org.asteriskjava.manager.event.CdrEvent;
import org.asteriskjava.manager.event.ConnectEvent;
import org.asteriskjava.manager.event.DbGetResponseEvent;
import org.asteriskjava.manager.event.DialEvent;
import org.asteriskjava.manager.event.DisconnectEvent;
import org.asteriskjava.manager.event.DtmfEvent;
import org.asteriskjava.manager.event.HangupEvent;
import org.asteriskjava.manager.event.JoinEvent;
import org.asteriskjava.manager.event.LeaveEvent;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.event.MonitorStartEvent;
import org.asteriskjava.manager.event.MonitorStopEvent;
import org.asteriskjava.manager.event.NewCallerIdEvent;
import org.asteriskjava.manager.event.NewChannelEvent;
import org.asteriskjava.manager.event.NewExtenEvent;
import org.asteriskjava.manager.event.NewStateEvent;
import org.asteriskjava.manager.event.OriginateResponseEvent;
import org.asteriskjava.manager.event.ParkedCallEvent;
import org.asteriskjava.manager.event.ParkedCallGiveUpEvent;
import org.asteriskjava.manager.event.ParkedCallTimeOutEvent;
import org.asteriskjava.manager.event.PeerEntryEvent;
import org.asteriskjava.manager.event.QueueCallerJoinEvent;
import org.asteriskjava.manager.event.QueueCallerLeaveEvent;
import org.asteriskjava.manager.event.QueueMemberAddedEvent;
import org.asteriskjava.manager.event.QueueMemberPausedEvent;
import org.asteriskjava.manager.event.QueueMemberPenaltyEvent;
import org.asteriskjava.manager.event.QueueMemberRemovedEvent;
import org.asteriskjava.manager.event.QueueMemberStatusEvent;
import org.asteriskjava.manager.event.RenameEvent;
import org.asteriskjava.manager.event.ResponseEvent;
import org.asteriskjava.manager.event.UnparkedCallEvent;
import org.asteriskjava.manager.event.VarSetEvent;
import org.asteriskjava.manager.response.CommandResponse;
import org.asteriskjava.manager.response.GetConfigResponse;
import org.asteriskjava.manager.response.MailboxCountResponse;
import org.asteriskjava.manager.response.ManagerError;
import org.asteriskjava.manager.response.ManagerResponse;
import org.asteriskjava.manager.response.ModuleCheckResponse;
import org.asteriskjava.util.AstUtil;
import org.asteriskjava.util.DateUtil;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;

/**
 * Default implementation of the {@link AsteriskServer} interface.
 *
 * @author srt
 * @version $Id$
 */
public class AsteriskServerImpl extends Lockable implements AsteriskServer, ManagerEventListener
{
    private static final String ACTION_ID_PREFIX_ORIGINATE = "AJ_ORIGINATE_";
    private static final String SHOW_VERSION_COMMAND = "show version";
    private static final String SHOW_VERSION_1_6_COMMAND = "core show version";
    private static final String SHOW_VERSION_FILES_COMMAND = "show version files";
    private static final String SHOW_VERSION_FILES_1_6_COMMAND = "core show file version";
    private static final Pattern SHOW_VERSION_FILES_PATTERN = Pattern.compile("^([\\S]+)\\s+Revision: ([0-9\\.]+)");
    private static final String SHOW_VOICEMAIL_USERS_COMMAND = "show voicemail users";
    private static final String SHOW_VOICEMAIL_USERS_1_6_COMMAND = "voicemail show users";
    private static final Pattern SHOW_VOICEMAIL_USERS_PATTERN = Pattern.compile("^(\\S+)\\s+(\\S+)\\s+(.{25})");

    private final Log logger = LogFactory.getLog(this.getClass());

    /**
     * The underlying manager connection used to receive events from Asterisk.
     */
    private ManagerConnection eventConnection;
    private ManagerEventListener eventListener = null;
    private ManagerEventListenerProxy managerEventListenerProxy;

    private boolean initialized = false;
    private boolean initializing = false;

    final LockableSet listeners;

    final ChannelManager channelManager;
    final MeetMeManager meetMeManager;
    final QueueManager queueManager;
    final AgentManager agentManager;

    /**
     * The exact version string of the Asterisk server we are connected to.
     * 

* Contains null until lazily initialized. */ private String version; /** * Holds the version of Asterisk's source files. *

* That corresponds to the output of the CLI command * show version files. *

* Contains null until lazily initialized. */ private LockableMap versions; /** * Maps the traceId to the corresponding callback data. */ private final LockableMap originateCallbacks; private final AtomicLong idCounter; /* config options */ /** * Flag to skip initializing queues as that results in a timeout on Asterisk * 1.0.x. */ private boolean skipQueues; /** * Set to true to not handle ManagerEvents in the reader tread * but process them asynchronously. This is a good idea :) */ private boolean asyncEventHandling = true; /** * The chainListener allows a listener to receive manager events after they * have been processed by the AsteriskServer. If the AsteriskServer is * handling messages using the asyncEventHandling then these messages will * also be async. You would use the chainListener if you are processing raw * events and using the AJ live ChannelManager. If you don't use the chain * listener then you can't be certain that a channel name passed in a raw * event will match the channel name held by the Channel Manager. By * chaining events you can be certain that events such as channel Rename * events have been processed by the live ChannelManager before you receive * an event and as such the names will always match. */ private LockableList chainListeners = new LockableList<>(new ArrayList<>()); /** * Creates a new instance. */ public AsteriskServerImpl() { idCounter = new AtomicLong(); listeners = new LockableSet<>(new LinkedHashSet<>()); originateCallbacks = new LockableMap<>(new HashMap<>()); channelManager = new ChannelManager(this); agentManager = new AgentManager(this); meetMeManager = new MeetMeManager(this, channelManager); queueManager = new QueueManager(this, channelManager); } /** * Creates a new instance. * * @param eventConnection the ManagerConnection to use for receiving events * from Asterisk. */ public AsteriskServerImpl(ManagerConnection eventConnection) { this(); setManagerConnection(eventConnection); // todo: !!! Possible bug !!!: // call to overridable method // over object construction } /** * Determines if queue status is retrieved at startup. If you don't need * queue information and still run Asterisk 1.0.x you can set this to * true to circumvent the startup delay caused by the missing * QueueStatusComplete event.
* Default is false. * * @param skipQueues true to skip queue initialization, * false to not skip. * @since 0.2 */ public void setSkipQueues(boolean skipQueues) { this.skipQueues = skipQueues; } public void setManagerConnection(ManagerConnection eventConnection) { if (this.eventConnection != null) { throw new IllegalStateException("ManagerConnection already set."); } this.eventConnection = eventConnection; } public ManagerConnection getManagerConnection() { return eventConnection; } public void initialize() throws ManagerCommunicationException { initializeIfNeeded(); } private void initializeIfNeeded() throws ManagerCommunicationException { try (LockCloser closer = this.withLock()) { if (initialized || initializing) { return; } if (asyncEventHandling && managerEventListenerProxy == null) { managerEventListenerProxy = new ManagerEventListenerProxy(this); eventConnection.addEventListener(managerEventListenerProxy); } else if (!asyncEventHandling && eventListener == null) { eventListener = this; eventConnection.addEventListener(eventListener); } initializing = true; if (eventConnection.getState() == ManagerConnectionState.INITIAL || eventConnection.getState() == ManagerConnectionState.DISCONNECTED) { try { eventConnection.login(); } catch (Exception e) { throw new ManagerCommunicationException("Unable to login: " + e.getMessage(), e); } } channelManager.initialize(); agentManager.initialize(); meetMeManager.initialize(); if (!skipQueues) { queueManager.initialize(); } if (asyncEventHandling && managerEventListenerProxy == null) { managerEventListenerProxy = new ManagerEventListenerProxy(this); eventConnection.addEventListener(managerEventListenerProxy); } else if (!asyncEventHandling && eventListener == null) { eventListener = this; eventConnection.addEventListener(eventListener); } logger.info("Initializing done"); initializing = false; initialized = true; } } /* Implementation of the AsteriskServer interface */ public AsteriskChannel originateToExtension(String channel, String context, String exten, int priority, long timeout) throws ManagerCommunicationException, NoSuchChannelException { return originateToExtension(channel, context, exten, priority, timeout, null, null); } public AsteriskChannel originateToExtension(String channel, String context, String exten, int priority, long timeout, CallerId callerId, Map variables) throws ManagerCommunicationException, NoSuchChannelException { final OriginateAction originateAction; originateAction = new OriginateAction(); originateAction.setChannel(channel); originateAction.setContext(context); originateAction.setExten(exten); originateAction.setPriority(priority); originateAction.setTimeout(timeout); if (callerId != null) { originateAction.setCallerId(callerId.toString()); } originateAction.setVariables(variables); return originate(originateAction); } public AsteriskChannel originateToApplication(String channel, String application, String data, long timeout) throws ManagerCommunicationException, NoSuchChannelException { return originateToApplication(channel, application, data, timeout, null, null); } public AsteriskChannel originateToApplication(String channel, String application, String data, long timeout, CallerId callerId, Map variables) throws ManagerCommunicationException, NoSuchChannelException { final OriginateAction originateAction; originateAction = new OriginateAction(); originateAction.setChannel(channel); originateAction.setApplication(application); originateAction.setData(data); originateAction.setTimeout(timeout); if (callerId != null) { originateAction.setCallerId(callerId.toString()); } originateAction.setVariables(variables); return originate(originateAction); } public AsteriskChannel originate(OriginateAction originateAction) throws ManagerCommunicationException, NoSuchChannelException { final ResponseEvents responseEvents; final Iterator responseEventIterator; String uniqueId; AsteriskChannel channel = null; // must set async to true to receive OriginateEvents. originateAction.setAsync(Boolean.TRUE); initializeIfNeeded(); // 2000 ms extra for the OriginateFailureEvent should be fine responseEvents = sendEventGeneratingAction(originateAction, originateAction.getTimeout() + 2000); responseEventIterator = responseEvents.getEvents().iterator(); if (responseEventIterator.hasNext()) { ResponseEvent responseEvent; responseEvent = responseEventIterator.next(); if (responseEvent instanceof OriginateResponseEvent) { uniqueId = ((OriginateResponseEvent) responseEvent).getUniqueId(); logger.debug(responseEvent.getClass().getName() + " received with uniqueId " + uniqueId); channel = getChannelById(uniqueId); } } if (channel == null) { throw new NoSuchChannelException("Channel '" + originateAction.getChannel() + "' is not available"); } return channel; } public void originateToExtensionAsync(String channel, String context, String exten, int priority, long timeout, OriginateCallback cb) throws ManagerCommunicationException { originateToExtensionAsync(channel, context, exten, priority, timeout, null, null, cb); } public void originateToExtensionAsync(String channel, String context, String exten, int priority, long timeout, CallerId callerId, Map variables, OriginateCallback cb) throws ManagerCommunicationException { final OriginateAction originateAction; originateAction = new OriginateAction(); originateAction.setChannel(channel); originateAction.setContext(context); originateAction.setExten(exten); originateAction.setPriority(priority); originateAction.setTimeout(timeout); if (callerId != null) { originateAction.setCallerId(callerId.toString()); } originateAction.setVariables(variables); originateAsync(originateAction, cb); } public void originateToApplicationAsync(String channel, String application, String data, long timeout, OriginateCallback cb) throws ManagerCommunicationException { originateToApplicationAsync(channel, application, data, timeout, null, null, cb); } public void originateToApplicationAsync(String channel, String application, String data, long timeout, CallerId callerId, Map variables, OriginateCallback cb) throws ManagerCommunicationException { final OriginateAction originateAction; originateAction = new OriginateAction(); originateAction.setChannel(channel); originateAction.setApplication(application); originateAction.setData(data); originateAction.setTimeout(timeout); if (callerId != null) { originateAction.setCallerId(callerId.toString()); } originateAction.setVariables(variables); originateAsync(originateAction, cb); } public void originateAsync(OriginateAction originateAction, OriginateCallback cb) throws ManagerCommunicationException { final Map variables; final String traceId; traceId = ACTION_ID_PREFIX_ORIGINATE + idCounter.getAndIncrement(); if (originateAction.getVariables() == null) { variables = new HashMap<>(); } else { variables = new HashMap<>(originateAction.getVariables()); } // prefix variable name by "__" to enable variable inheritence across // channels variables.put("__" + Constants.VARIABLE_TRACE_ID, traceId); originateAction.setVariables(variables); // async must be set to true to receive OriginateEvents. originateAction.setAsync(Boolean.TRUE); originateAction.setActionId(traceId); if (cb != null) { final OriginateCallbackData callbackData; callbackData = new OriginateCallbackData(originateAction, DateUtil.getDate(), cb); // register callback try (LockCloser closer = originateCallbacks.withLock()) { originateCallbacks.put(traceId, callbackData); } } initializeIfNeeded(); sendActionOnEventConnection(originateAction); } public Collection getChannels() throws ManagerCommunicationException { initializeIfNeeded(); return channelManager.getChannels(); } public AsteriskChannel getChannelByName(String name) throws ManagerCommunicationException { initializeIfNeeded(); return channelManager.getChannelImplByName(name); } public AsteriskChannel getChannelById(String id) throws ManagerCommunicationException { initializeIfNeeded(); return channelManager.getChannelImplById(id); } public Collection getMeetMeRooms() throws ManagerCommunicationException { initializeIfNeeded(); return meetMeManager.getMeetMeRooms(); } public MeetMeRoom getMeetMeRoom(String name) throws ManagerCommunicationException { initializeIfNeeded(); return meetMeManager.getOrCreateRoomImpl(name); } public Collection getQueues() throws ManagerCommunicationException { initializeIfNeeded(); return queueManager.getQueues(); } @Override public AsteriskQueue getQueueByName(String queueName) { initializeIfNeeded(); return queueManager.getQueueByName(queueName); } @Override public List getQueuesUpdatedAfter(Date date) { initializeIfNeeded(); return queueManager.getQueuesUpdatedAfter(date); } public String getVersion() throws ManagerCommunicationException { try (LockCloser closer = this.withLock()) { final ManagerResponse response; final String command; initializeIfNeeded(); if (version == null) { if (eventConnection.getVersion().isAtLeast(AsteriskVersion.ASTERISK_1_6)) { command = SHOW_VERSION_1_6_COMMAND; } else { command = SHOW_VERSION_COMMAND; } response = sendAction(new CommandAction(command)); if (response instanceof CommandResponse) { final List result; result = ((CommandResponse) response).getResult(); if (!result.isEmpty()) { version = result.get(0); } } else { logger.error("Response to CommandAction(\"" + command + "\") was not a CommandResponse but " + response); } } return version; } } public int[] getVersion(String file) throws ManagerCommunicationException { String fileVersion = null; String[] parts; int[] intParts; initializeIfNeeded(); if (versions == null) { LockableMap map; ManagerResponse response; map = new LockableMap<>(new HashMap<>()); try { final String command; if (eventConnection.getVersion().isAtLeast(AsteriskVersion.ASTERISK_1_6)) { command = SHOW_VERSION_FILES_1_6_COMMAND; } else { command = SHOW_VERSION_FILES_COMMAND; } response = sendAction(new CommandAction(command)); if (response instanceof CommandResponse) { List result; result = ((CommandResponse) response).getResult(); for (int i = 2; i < result.size(); i++) { String line; Matcher matcher; line = result.get(i); matcher = SHOW_VERSION_FILES_PATTERN.matcher(line); if (matcher.find()) { String key = matcher.group(1); String value = matcher.group(2); map.put(key, value); } } fileVersion = map.get(file); versions = map; } else { logger.error("Response to CommandAction(\"" + command + "\") was not a CommandResponse but " + response); } } catch (Exception e) { logger.warn("Unable to send '" + SHOW_VERSION_FILES_COMMAND + "' command.", e); } } else { try (LockCloser closer = versions.withLock()) { fileVersion = versions.get(file); } } if (fileVersion == null) { return null; } parts = fileVersion.split("\\."); intParts = new int[parts.length]; for (int i = 0; i < parts.length; i++) { try { intParts[i] = Integer.parseInt(parts[i]); } catch (NumberFormatException e) { intParts[i] = 0; } } return intParts; } public String getGlobalVariable(String variable) throws ManagerCommunicationException { ManagerResponse response; String value; initializeIfNeeded(); response = sendAction(new GetVarAction(variable)); if (response instanceof ManagerError) { return null; } value = response.getAttribute("Value"); if (value == null) { value = response.getAttribute(variable); // for Asterisk 1.0.x } return value; } public void setGlobalVariable(String variable, String value) throws ManagerCommunicationException { ManagerResponse response; initializeIfNeeded(); response = sendAction(new SetVarAction(variable, value)); if (response instanceof ManagerError) { logger.error("Unable to set global variable '" + variable + "' to '" + value + "':" + response.getMessage()); } } public Collection getVoicemailboxes() throws ManagerCommunicationException { final Collection voicemailboxes; ManagerResponse response; final List result; initializeIfNeeded(); voicemailboxes = new ArrayList<>(); if (eventConnection.getVersion().isAtLeast(AsteriskVersion.ASTERISK_1_6)) { response = sendAction(new CommandAction(SHOW_VOICEMAIL_USERS_1_6_COMMAND)); } else { response = sendAction(new CommandAction(SHOW_VOICEMAIL_USERS_COMMAND)); } if (!(response instanceof CommandResponse)) { logger.error("Response to CommandAction(\"" + SHOW_VOICEMAIL_USERS_COMMAND + "\") was not a CommandResponse but " + response); return voicemailboxes; } result = ((CommandResponse) response).getResult(); if (result == null || result.isEmpty()) { return voicemailboxes; } // remove headline result.remove(0); for (String line : result) { final Matcher matcher; final Voicemailbox voicemailbox; final String context; final String mailbox; final String user; matcher = SHOW_VOICEMAIL_USERS_PATTERN.matcher(line); if (!matcher.find()) { continue; } context = matcher.group(1); mailbox = matcher.group(2); user = matcher.group(3).trim(); voicemailbox = new Voicemailbox(mailbox, context, user); voicemailboxes.add(voicemailbox); } // get message count for each mailbox for (Voicemailbox voicemailbox : voicemailboxes) { final String fullname; fullname = voicemailbox.getMailbox() + "@" + voicemailbox.getContext(); response = sendAction(new MailboxCountAction(fullname)); if (response instanceof MailboxCountResponse) { MailboxCountResponse mailboxCountResponse; mailboxCountResponse = (MailboxCountResponse) response; voicemailbox.setNewMessages(mailboxCountResponse.getNewMessages()); voicemailbox.setOldMessages(mailboxCountResponse.getOldMessages()); } else { logger.error("Response to MailboxCountAction was not a MailboxCountResponse but " + response); } } return voicemailboxes; } public List executeCliCommand(String command) throws ManagerCommunicationException { final ManagerResponse response; initializeIfNeeded(); response = sendAction(new CommandAction(command)); if (!(response instanceof CommandResponse)) { throw new ManagerCommunicationException( "Response to CommandAction(\"" + command + "\") was not a CommandResponse but " + response, null); } return ((CommandResponse) response).getResult(); } public boolean isModuleLoaded(String module) throws ManagerCommunicationException { return sendAction(new ModuleCheckAction(module)) instanceof ModuleCheckResponse; } public void loadModule(String module) throws ManagerCommunicationException { sendModuleLoadAction(module, ModuleLoadAction.LOAD_TYPE_LOAD); } public void unloadModule(String module) throws ManagerCommunicationException { sendModuleLoadAction(module, ModuleLoadAction.LOAD_TYPE_UNLOAD); } public void reloadModule(String module) throws ManagerCommunicationException { sendModuleLoadAction(module, ModuleLoadAction.LOAD_TYPE_RELOAD); } public void reloadAllModules() throws ManagerCommunicationException { sendModuleLoadAction(null, ModuleLoadAction.LOAD_TYPE_RELOAD); } protected void sendModuleLoadAction(String module, String loadType) throws ManagerCommunicationException { final ManagerResponse response; response = sendAction(new ModuleLoadAction(module, loadType)); if (response instanceof ManagerError) { final ManagerError error = (ManagerError) response; throw new ManagerCommunicationException(error.getMessage(), null); } } public ConfigFile getConfig(String filename) throws ManagerCommunicationException { final ManagerResponse response; final GetConfigResponse getConfigResponse; initializeIfNeeded(); response = sendAction(new GetConfigAction(filename)); if (!(response instanceof GetConfigResponse)) { throw new ManagerCommunicationException( "Response to GetConfigAction(\"" + filename + "\") was not a CommandResponse but " + response, null); } getConfigResponse = (GetConfigResponse) response; final Map categoryMap = getConfigResponse.getCategories(); final Map> categories = new LinkedHashMap<>(); for (Map.Entry categoryEntry : categoryMap.entrySet()) { final List lines; final Map lineMap = getConfigResponse.getLines(categoryEntry.getKey()); if (lineMap == null) { lines = new ArrayList<>(); } else { lines = new ArrayList<>(lineMap.values()); } categories.put(categoryEntry.getValue(), lines); } return new ConfigFileImpl(filename, categories); } @Override public void addAsteriskServerListener(AsteriskServerListener listener) throws ManagerCommunicationException { initializeIfNeeded(); try (LockCloser closer = listeners.withLock()) { if (!listeners.contains(listener)) { listeners.add(listener); } } } @Override public void removeAsteriskServerListener(AsteriskServerListener listener) { try (LockCloser closer = listeners.withLock()) { listeners.remove(listener); } } @Override public boolean isAsteriskServerListening(AsteriskServerListener listener) { return listeners.contains(listener); } public void addChainListener(ManagerEventListener chainListener) { try (LockCloser closer = this.chainListeners.withLock()) { if (!this.chainListeners.contains(chainListener)) this.chainListeners.add(chainListener); } } public void removeChainListener(ManagerEventListener chainListener) { this.chainListeners.remove(chainListener); } void fireNewAsteriskChannel(AsteriskChannel channel) { try (LockCloser closer = listeners.withLock()) { for (AsteriskServerListener listener : listeners) { try { listener.onNewAsteriskChannel(channel); } catch (Exception e) { logger.warn("Exception in onNewAsteriskChannel()", e); } } } } void fireNewMeetMeUser(MeetMeUser user) { try (LockCloser closer = listeners.withLock()) { for (AsteriskServerListener listener : listeners) { try { listener.onNewMeetMeUser(user); } catch (Exception e) { logger.warn("Exception in onNewMeetMeUser()", e); } } } } ManagerResponse sendActionOnEventConnection(ManagerAction action) throws ManagerCommunicationException { try { return eventConnection.sendAction(action); } catch (Exception e) { throw ManagerCommunicationExceptionMapper.mapSendActionException(action.getAction(), e); } } ManagerResponse sendAction(ManagerAction action) throws ManagerCommunicationException { // return connectionPool.sendAction(action); try { return eventConnection.sendAction(action); } catch (Exception e) { throw ManagerCommunicationExceptionMapper.mapSendActionException(action.getAction(), e); } } ResponseEvents sendEventGeneratingAction(EventGeneratingAction action) throws ManagerCommunicationException { // return connectionPool.sendEventGeneratingAction(action); try { return eventConnection.sendEventGeneratingAction(action); } catch (Exception e) { throw ManagerCommunicationExceptionMapper.mapSendActionException(action.getAction(), e); } } ResponseEvents sendEventGeneratingAction(EventGeneratingAction action, long timeout) throws ManagerCommunicationException { // return connectionPool.sendEventGeneratingAction(action, timeout); try { return eventConnection.sendEventGeneratingAction(action, timeout); } catch (Exception e) { throw ManagerCommunicationExceptionMapper.mapSendActionException(action.getAction(), e); } } OriginateCallbackData getOriginateCallbackDataByTraceId(String traceId) { try (LockCloser closer = originateCallbacks.withLock()) { return originateCallbacks.get(traceId); } } /* Implementation of the ManagerEventListener interface */ /** * Handles all events received from the Asterisk server.
* Events are queued until channels and queues are initialized and then * delegated to the dispatchEvent method. */ public void onManagerEvent(ManagerEvent event) { // Handle Channel related events if (event instanceof ConnectEvent) { handleConnectEvent((ConnectEvent) event); } else if (event instanceof DisconnectEvent) { handleDisconnectEvent((DisconnectEvent) event); } else if (event instanceof NewChannelEvent) { channelManager.handleNewChannelEvent((NewChannelEvent) event); } else if (event instanceof NewExtenEvent) { channelManager.handleNewExtenEvent((NewExtenEvent) event); } else if (event instanceof NewStateEvent) { channelManager.handleNewStateEvent((NewStateEvent) event); } else if (event instanceof NewCallerIdEvent) { channelManager.handleNewCallerIdEvent((NewCallerIdEvent) event); } else if (event instanceof DialEvent) { channelManager.handleDialEvent((DialEvent) event); } else if (event instanceof BridgeEvent) { channelManager.handleBridgeEvent((BridgeEvent) event); } else if (event instanceof RenameEvent) { channelManager.handleRenameEvent((RenameEvent) event); } else if (event instanceof HangupEvent) { channelManager.handleHangupEvent((HangupEvent) event); } else if (event instanceof CdrEvent) { channelManager.handleCdrEvent((CdrEvent) event); } else if (event instanceof VarSetEvent) { channelManager.handleVarSetEvent((VarSetEvent) event); } else if (event instanceof DtmfEvent) { channelManager.handleDtmfEvent((DtmfEvent) event); } else if (event instanceof MonitorStartEvent) { channelManager.handleMonitorStartEvent((MonitorStartEvent) event); } else if (event instanceof MonitorStopEvent) { channelManager.handleMonitorStopEvent((MonitorStopEvent) event); } // End of channel related events // Handle parking related event else if (event instanceof ParkedCallEvent) { channelManager.handleParkedCallEvent((ParkedCallEvent) event); } else if (event instanceof ParkedCallGiveUpEvent) { channelManager.handleParkedCallGiveUpEvent((ParkedCallGiveUpEvent) event); } else if (event instanceof ParkedCallTimeOutEvent) { channelManager.handleParkedCallTimeOutEvent((ParkedCallTimeOutEvent) event); } else if (event instanceof UnparkedCallEvent) { channelManager.handleUnparkedCallEvent((UnparkedCallEvent) event); } // End of parking related events // Handle queue related event else if (event instanceof JoinEvent) { queueManager.handleJoinEvent((JoinEvent) event); } else if (event instanceof LeaveEvent) { queueManager.handleLeaveEvent((LeaveEvent) event); } else if (event instanceof QueueMemberStatusEvent) { queueManager.handleQueueMemberStatusEvent((QueueMemberStatusEvent) event); } else if (event instanceof QueueMemberPenaltyEvent) { queueManager.handleQueueMemberPenaltyEvent((QueueMemberPenaltyEvent) event); } else if (event instanceof QueueMemberAddedEvent) { queueManager.handleQueueMemberAddedEvent((QueueMemberAddedEvent) event); } else if (event instanceof QueueMemberRemovedEvent) { queueManager.handleQueueMemberRemovedEvent((QueueMemberRemovedEvent) event); } else if (event instanceof QueueMemberPausedEvent) { queueManager.handleQueueMemberPausedEvent((QueueMemberPausedEvent) event); } else if (event instanceof QueueCallerJoinEvent) { queueManager.handleJoinEvent((QueueCallerJoinEvent) event); } else if (event instanceof QueueCallerLeaveEvent) { queueManager.handleLeaveEvent((QueueCallerLeaveEvent) event); } // >>>>>> AJ 94 // Handle meetMeEvents else if (event instanceof AbstractMeetMeEvent) { meetMeManager.handleMeetMeEvent((AbstractMeetMeEvent) event); } else if (event instanceof OriginateResponseEvent) { handleOriginateEvent((OriginateResponseEvent) event); } // Handle agents-related events else if (event instanceof AgentsEvent) { agentManager.handleAgentsEvent((AgentsEvent) event); } else if (event instanceof AgentCalledEvent) { agentManager.handleAgentCalledEvent((AgentCalledEvent) event); } else if (event instanceof AgentConnectEvent) { agentManager.handleAgentConnectEvent((AgentConnectEvent) event); } else if (event instanceof AgentCompleteEvent) { agentManager.handleAgentCompleteEvent((AgentCompleteEvent) event); } else if (event instanceof AgentCallbackLoginEvent) { agentManager.handleAgentCallbackLoginEvent((AgentCallbackLoginEvent) event); } else if (event instanceof AgentCallbackLogoffEvent) { agentManager.handleAgentCallbackLogoffEvent((AgentCallbackLogoffEvent) event); } else if (event instanceof AgentLoginEvent) { agentManager.handleAgentLoginEvent((AgentLoginEvent) event); } else if (event instanceof AgentLogoffEvent) { agentManager.handleAgentLogoffEvent((AgentLogoffEvent) event); } // End of agent-related events // dispatch the events to the chainListener if they exist. fireChainListeners(event); } /** * dispatch the event to the chainListener if they exist. * * @param event */ private void fireChainListeners(ManagerEvent event) { try (LockCloser closer = this.chainListeners.withLock()) { for (ManagerEventListener listener : this.chainListeners) listener.onManagerEvent(event); } } /* * Resets the internal state when the connection to the asterisk server is * lost. */ private void handleDisconnectEvent(DisconnectEvent disconnectEvent) { // reset version information as it might have changed while Asterisk // restarted version = null; versions = null; // same for channels, agents and queues rooms, they are reinitialized // when reconnected channelManager.disconnected(); agentManager.disconnected(); meetMeManager.disconnected(); queueManager.disconnected(); initialized = false; initializing = false; } /* * Requests the current state from the asterisk server after the connection * to the asterisk server is restored. */ private void handleConnectEvent(ConnectEvent connectEvent) { try { initialize(); channelManager.initialize(); agentManager.initialize(); meetMeManager.initialize(); if (!skipQueues) { queueManager.initialize(); } logger.info("Initializing done"); initialized = true; initializing = false; } catch (Exception e) { logger.error("Unable to reinitialize state after reconnection", e); } } private void handleOriginateEvent(OriginateResponseEvent originateEvent) { final String traceId; final OriginateCallbackData callbackData; final OriginateCallback cb; final AsteriskChannelImpl channel; final AsteriskChannelImpl otherChannel; // the other side if local // channel traceId = originateEvent.getActionId(); if (traceId == null) { return; } try (LockCloser closer = originateCallbacks.withLock()) { callbackData = originateCallbacks.get(traceId); if (callbackData == null) { return; } originateCallbacks.remove(traceId); } cb = callbackData.getCallback(); if (!AstUtil.isNull(originateEvent.getUniqueId())) { channel = channelManager.getChannelImplById(originateEvent.getUniqueId()); } else { channel = callbackData.getChannel(); } try { if (channel == null) { final LiveException cause; cause = new NoSuchChannelException( "Channel '" + callbackData.getOriginateAction().getChannel() + "' is not available"); cb.onFailure(cause); return; } if (channel.wasInState(ChannelState.UP)) { cb.onSuccess(channel); return; } if (channel.wasBusy()) { cb.onBusy(channel); return; } otherChannel = channelManager.getOtherSideOfLocalChannel(channel); // special treatment of local channels: // the interesting things happen to the other side so we have a look // at that if (otherChannel != null) { final AsteriskChannel dialedChannel; dialedChannel = otherChannel.getDialedChannel(); // on busy the other channel is in state busy when we receive // the originate event if (otherChannel.wasBusy()) { cb.onBusy(channel); return; } // alternative: // on busy the dialed channel is hung up when we receive the // originate event having a look at the hangup cause reveals the // information we are interested in // this alternative has the drawback that there might by // multiple channels that have been dialed by the local channel // but we only look at the last one. if (dialedChannel != null && dialedChannel.wasBusy()) { cb.onBusy(channel); return; } } // if nothing else matched we asume no answer cb.onNoAnswer(channel); } catch (Throwable t) { logger.warn("Exception dispatching originate progress", t); } } @Override public void shutdown() { if (eventConnection != null && (eventConnection.getState() == ManagerConnectionState.CONNECTED || eventConnection.getState() == ManagerConnectionState.RECONNECTING)) { try { eventConnection.logoff(); } catch (Exception ignore) { } } if (managerEventListenerProxy != null) { if (eventConnection != null) { eventConnection.removeEventListener(managerEventListenerProxy); } managerEventListenerProxy.shutdown(); } if (eventConnection != null && eventListener != null) { eventConnection.removeEventListener(eventListener); } managerEventListenerProxy = null; eventListener = null; if (initialized) {// incredible, but it happened handleDisconnectEvent(null); } // i }// shutdown public List getPeerEntries() throws ManagerCommunicationException { ResponseEvents responseEvents = sendEventGeneratingAction(new SipPeersAction(), 2000); List peerEntries = new ArrayList<>(30); for (ResponseEvent re : responseEvents.getEvents()) { if (re instanceof PeerEntryEvent) { peerEntries.add((PeerEntryEvent) re); } } return peerEntries; } public DbGetResponseEvent dbGet(String family, String key) throws ManagerCommunicationException { ResponseEvents responseEvents = sendEventGeneratingAction(new DbGetAction(family, key), 2000); DbGetResponseEvent dbgre = null; for (ResponseEvent re : responseEvents.getEvents()) { dbgre = (DbGetResponseEvent) re; } return dbgre; } public void dbDel(String family, String key) throws ManagerCommunicationException { // The following only works with BRIStuffed asrterisk: sendAction(new // DbDelAction(family,key)); // Use cli command instead ... sendAction(new CommandAction("database del " + family + " " + key)); } public void dbPut(String family, String key, String value) throws ManagerCommunicationException { sendAction(new DbPutAction(family, key, value)); } public AsteriskChannel getChannelByNameAndActive(String name) throws ManagerCommunicationException { initializeIfNeeded(); return channelManager.getChannelImplByNameAndActive(name); } public Collection getAgents() throws ManagerCommunicationException { initializeIfNeeded(); return agentManager.getAgents(); } void fireNewAgent(AsteriskAgentImpl agent) { try (LockCloser closer = listeners.withLock()) { for (AsteriskServerListener listener : listeners) { try { listener.onNewAgent(agent); } catch (Exception e) { logger.warn("Exception in onNewAgent()", e); } } } } void fireNewQueueEntry(AsteriskQueueEntry entry) { try (LockCloser closer = listeners.withLock()) { for (AsteriskServerListener listener : listeners) { try { listener.onNewQueueEntry(entry); } catch (Exception e) { logger.warn("Exception in onNewQueueEntry()", e); } } } } /* OCTAVIO LUNA */ @Override public void forceQueuesMonitor(boolean force) { queueManager.forceQueuesMonitor(force); } @Override public boolean isQueuesMonitorForced() { return queueManager.isQueuesMonitorForced(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy