[Asterisk-java-cvs] CVS: asterisk-java/src/java/net/sf/asterisk/manager ResponseEvents.java,NONE,1.1
Brought to you by:
srt
From: Stefan R. <sr...@us...> - 2005-07-16 21:48:25
|
Update of /cvsroot/asterisk-java/asterisk-java/src/java/net/sf/asterisk/manager In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11254/src/java/net/sf/asterisk/manager Modified Files: DefaultManagerConnection.java ManagerConnection.java Added Files: ResponseEvents.java Log Message: Introduced EventGeneratingActions --- NEW FILE: ResponseEvents.java --- /* * Copyright 2004-2005 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 net.sf.asterisk.manager; import java.util.Collection; import net.sf.asterisk.manager.response.ManagerResponse; /** * Contains the result of executing an EventGeneratingAction, that is the * ManagerResponse and any received ManagerEvents. * * @see net.sf.asterisk.manager.action.EventGeneratingAction * @author srt * @version $Id: ResponseEvents.java,v 1.1 2005/07/16 21:48:15 srt Exp $ * @since 0.2 */ public interface ResponseEvents { /** * Returns the ManagerResponse received. * * @return the ManagerResponse received. */ ManagerResponse getResponse(); /** * Returns a Collection of ManagerEvents that have been received including * the last one that indicates completion. * * @return a Collection of ManagerEvents received. */ Collection getEvents(); } Index: DefaultManagerConnection.java =================================================================== RCS file: /cvsroot/asterisk-java/asterisk-java/src/java/net/sf/asterisk/manager/DefaultManagerConnection.java,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -p -r1.20 -r1.21 --- DefaultManagerConnection.java 16 Jul 2005 00:17:26 -0000 1.20 +++ DefaultManagerConnection.java 16 Jul 2005 21:48:16 -0000 1.21 @@ -29,14 +29,17 @@ import java.util.Map; import net.sf.asterisk.io.SocketConnectionFacade; import net.sf.asterisk.io.SocketConnectionFacadeImpl; import net.sf.asterisk.manager.action.ChallengeAction; +import net.sf.asterisk.manager.action.EventGeneratingAction; import net.sf.asterisk.manager.action.LoginAction; import net.sf.asterisk.manager.action.LogoffAction; import net.sf.asterisk.manager.action.ManagerAction; import net.sf.asterisk.manager.event.ConnectEvent; import net.sf.asterisk.manager.event.DisconnectEvent; import net.sf.asterisk.manager.event.ManagerEvent; +import net.sf.asterisk.manager.event.ResponseEvent; import net.sf.asterisk.manager.impl.ManagerReaderImpl; import net.sf.asterisk.manager.impl.ManagerWriterImpl; +import net.sf.asterisk.manager.impl.ResponseEventsImpl; import net.sf.asterisk.manager.response.ChallengeResponse; import net.sf.asterisk.manager.response.ManagerError; import net.sf.asterisk.manager.response.ManagerResponse; @@ -48,7 +51,8 @@ import net.sf.asterisk.util.LogFactory; * * @see net.sf.asterisk.manager.ManagerConnection * @author srt - * @version $Id$ + * @version $Id: DefaultManagerConnection.java,v 1.20 2005/07/16 00:17:26 srt + * Exp $ */ public class DefaultManagerConnection implements ManagerConnection, Dispatcher { @@ -57,17 +61,60 @@ public class DefaultManagerConnection im */ private final Log logger = LogFactory.getLog(getClass()); + /** + * Used to construct the internalActionId. + */ private long actionIdCount = 0; /* Config attributes */ + /** + * The Asterisk server to connect to. + */ private AsteriskServer asteriskServer; + + /** + * The username to use for login as defined in Asterisk's + * <code>manager.conf</code>. + */ protected String username; + + /** + * The password to use for login as defined in Asterisk's + * <code>manager.conf</code>. + */ protected String password; - private long defaultTimeout = 2000; + + /** + * The default timeout to wait for a ManagerResponse after sending a + * ManagerAction. + */ + private long defaultResponseTimeout = 2000; + + /** + * The default timeout to wait for the last ResponseEvent after sending an + * EventGeneratingAction. + */ + private long defaultEventTimeout = 5000; + + /** + * The time the calling thread is sleeping between checking if a reponse or + * the protocol identifer has been received. + */ private long sleepTime = 50; + + /** + * Should we continue to reconnect after an authentication failure? + */ private boolean keepAliveAfterAuthenticationFailure = false; + /** + * The socket to use for TCP/IP communication with Asterisk. + */ private SocketConnectionFacade socket; + + /** + * The thread that runs the reader. + */ private Thread readerThread; /** @@ -80,19 +127,60 @@ public class DefaultManagerConnection im */ private ManagerWriter writer; + /** + * The protocol identifer Asterisk sends on connect. + */ private String protocolIdentifier; + + /** + * Contains the registered handlers that process the ManagerResponses.<br> + * Key is the internalActionId of the Action sent and value the + * corresponding ResponseHandler. + */ private final Map responseHandlers; + + /** + * Contains the event handlers that handle ResponseEvents for the + * sendEventGeneratingAction methods.<br> + * Key is the internalActionId of the Action sent and value the + * corresponding EventHandler. + */ + private final Map responseEventHandlers; + + /** + * Contains the event handlers that users registered. + */ private final List eventHandlers; + + /** + * Should we attempt to reconnect when the connection is lost?<br> + * This is set to <code>true</code> after successful login and to + * <code>false</code> after logoff or after an authentication failure when + * keepAliveAfterAuthenticationFailure is <code>false</code>. + */ protected boolean keepAlive = false; + /** + * Creates a new instance. + */ public DefaultManagerConnection() { this.asteriskServer = new AsteriskServer(); this.responseHandlers = new HashMap(); + this.responseEventHandlers = new HashMap(); this.eventHandlers = new ArrayList(); } + /** + * Creates a new instance with the given connection parameters. + * + * @param hostname the hosname of the Asterisk server to connect to. + * @param port the port where Asterisk listens for incoming Manager API + * connections, usually 5038. + * @param username the username to use for login + * @param password the password to use for login + */ public DefaultManagerConnection(String hostname, int port, String username, String password) { @@ -104,6 +192,8 @@ public class DefaultManagerConnection im setPassword(password); } + // the following two methods can be overriden when running test cases to + // return a mock object protected ManagerReader createReader(Dispatcher dispatcher, AsteriskServer server) { @@ -161,27 +251,60 @@ public class DefaultManagerConnection im } /** - * Sets the time in milli seconds the synchronous method + * Sets the time in milliseconds the synchronous sendAction methods * {@link #sendAction(ManagerAction)} will wait for a response before * throwing a TimeoutException.<br> * Default is 2000. * - * @param defaultTimeout default timeout in milli seconds + * @param defaultTimeout default timeout in milliseconds + * @deprecated use {@link #setDefaultResponseTimeout(long)} instead */ public void setDefaultTimeout(long defaultTimeout) { - this.defaultTimeout = defaultTimeout; + setDefaultResponseTimeout(defaultTimeout); } /** - * Sets the time in milli seconds the synchronous methods + * Sets the time in milliseconds the synchronous method + * {@link #sendAction(ManagerAction)} will wait for a response before + * throwing a TimeoutException.<br> + * Default is 2000. + * + * @param defaultResponseTimeout default response timeout in milliseconds + * @since 0.2 + */ + public void setDefaultResponseTimeout(long defaultResponseTimeout) + { + this.defaultResponseTimeout = defaultResponseTimeout; + } + + /** + * Sets the time in milliseconds the synchronous method + * {@link #sendEventGeneratingAction(EventGeneratingAction)} will wait for a + * response and the last response event before throwing a TimeoutException.<br> + * Default is 5000. + * + * @param defaultEventTimeout default event timeout in milliseconds + * @since 0.2 + */ + public void setDefaultEventTimeout(long defaultEventTimeout) + { + this.defaultEventTimeout = defaultEventTimeout; + } + + /** + * Sets the time in milliseconds the synchronous methods * {@link #sendAction(ManagerAction)} and * {@link #sendAction(ManagerAction, long)} will sleep between two checks * for the arrival of a response. This value should be rather small.<br> + * The sleepTime attribute is also used when checking for the protocol + * identifer.<br> * Default is 50. * - * @param sleepTime time in milli seconds to sleep between two checks for - * the arrival of a responser + * @param sleepTime time in milliseconds to sleep between two checks for the + * arrival of a response or the protocol identifier + * @deprecated this has been replaced by an interrupt based response + * checking approach. */ public void setSleepTime(long sleepTime) { @@ -226,7 +349,7 @@ public class DefaultManagerConnection im public void login() throws IOException, AuthenticationFailedException, TimeoutException { - login(defaultTimeout); + login(defaultResponseTimeout); } /** @@ -256,6 +379,7 @@ public class DefaultManagerConnection im private void login(long timeout) throws IOException, AuthenticationFailedException, TimeoutException { + long start; long timeSpent; ChallengeAction challengeAction; ChallengeResponse challengeResponse; @@ -268,24 +392,24 @@ public class DefaultManagerConnection im connect(); } - timeSpent = 0; + start = System.currentTimeMillis(); while (getProtocolIdentifier() == null) { try { Thread.sleep(sleepTime); - timeSpent += sleepTime; - - if (timeSpent > timeout) - { - disconnect(); - throw new TimeoutException( - "Timeout waiting for protocol identifier"); - } } catch (InterruptedException e) { } + + timeSpent = System.currentTimeMillis() - start; + if (getProtocolIdentifier() == null && timeSpent > timeout) + { + disconnect(); + throw new TimeoutException( + "Timeout waiting for protocol identifier"); + } } challengeAction = new ChallengeAction(); @@ -300,7 +424,9 @@ public class DefaultManagerConnection im loginAction.setUsername(username); try { - MessageDigest md = MessageDigest.getInstance("MD5"); + MessageDigest md; + + md = MessageDigest.getInstance("MD5"); if (challenge != null) { md.update(challenge.getBytes()); @@ -326,8 +452,7 @@ public class DefaultManagerConnection im } // successfully logged in so assure that we keep trying to reconnect - // when - // disconnected + // when disconnected this.keepAlive = true; logger.info("Successfully logged in"); @@ -351,7 +476,7 @@ public class DefaultManagerConnection im this.socket = createSocket(); this.reader.setSocket(socket); - this.readerThread = new Thread(reader, "ManagerReaderThread"); + this.readerThread = new Thread(reader, "ManagerReader"); this.readerThread.start(); this.writer.setSocket(socket); @@ -373,7 +498,7 @@ public class DefaultManagerConnection im public synchronized boolean isConnected() { return socket != null && socket.isConnected(); // JDK 1.4 - //return socket != null; + // return socket != null; } /** @@ -395,6 +520,9 @@ public class DefaultManagerConnection im } } + /** + * Closes the socket connection. + */ private synchronized void disconnect() { if (this.socket != null) @@ -413,48 +541,53 @@ public class DefaultManagerConnection im } public ManagerResponse sendAction(ManagerAction action) throws IOException, - TimeoutException + TimeoutException, IllegalArgumentException, IllegalStateException { - return sendAction(action, defaultTimeout); + return sendAction(action, defaultResponseTimeout); } public ManagerResponse sendAction(ManagerAction action, long timeout) - throws IOException, TimeoutException + throws IOException, TimeoutException, IllegalArgumentException, + IllegalStateException { + long start; long timeSpent; ResponseHandlerResult result; ManagerResponseHandler callbackHandler; result = new ResponseHandlerResult(); - callbackHandler = new DefaultResponseHandler(result); + callbackHandler = new DefaultResponseHandler(result, Thread + .currentThread()); sendAction(action, callbackHandler); + start = System.currentTimeMillis(); timeSpent = 0; while (result.getResponse() == null) { try { - Thread.sleep(sleepTime); - timeSpent += sleepTime; - - if (timeSpent > timeout) - { - throw new TimeoutException( - "Timeout waiting for response to " - + action.getAction()); - } + Thread.sleep(timeout - timeSpent); } catch (InterruptedException ex) { } + + // still no response and timed out? + timeSpent = System.currentTimeMillis() - start; + if (result.getResponse() == null && timeSpent > timeout) + { + throw new TimeoutException("Timeout waiting for response to " + + action.getAction()); + } } return result.getResponse(); } public void sendAction(ManagerAction action, - ManagerResponseHandler callbackHandler) throws IOException + ManagerResponseHandler callbackHandler) throws IOException, + IllegalArgumentException, IllegalStateException { String internalActionId; @@ -474,6 +607,8 @@ public class DefaultManagerConnection im action.setActionId(Util.addInternalActionId(action.getActionId(), internalActionId)); + // if the callbackHandler is null the user is obviously not interested + // in the response, thats fine. if (callbackHandler != null) { synchronized (this.responseHandlers) @@ -485,9 +620,118 @@ public class DefaultManagerConnection im writer.sendAction(action); } + public ResponseEvents sendEventGeneratingAction(EventGeneratingAction action) + throws IOException, TimeoutException, IllegalArgumentException, + IllegalStateException + { + return sendEventGeneratingAction(action, defaultEventTimeout); + } + + public ResponseEvents sendEventGeneratingAction( + EventGeneratingAction action, long timeout) throws IOException, + TimeoutException, IllegalArgumentException, IllegalStateException + { + ResponseEventsImpl responseEvents; + ResponseEventHandler responseEventHandler; + String internalActionId; + long start; + long timeSpent; + + if (action == null) + { + throw new IllegalArgumentException( + "Unable to send action: action is null."); + } + else if (action.getActionCompleteEventClass() == null) + { + throw new IllegalArgumentException( + "Unable to send action: actionCompleteEventClass is null."); + } + else if (!ResponseEvent.class.isAssignableFrom(action + .getActionCompleteEventClass())) + { + throw new IllegalArgumentException( + "Unable to send action: actionCompleteEventClass is not a ResponseEvent."); + } + + if (socket == null) + { + throw new IllegalStateException("Unable to send " + + action.getAction() + " action: not connected."); + } + + responseEvents = new ResponseEventsImpl(); + responseEventHandler = new ResponseEventHandler(responseEvents, action + .getActionCompleteEventClass(), Thread.currentThread()); + + internalActionId = createInternalActionId(); + action.setActionId(Util.addInternalActionId(action.getActionId(), + internalActionId)); + + // register response handler... + synchronized (this.responseHandlers) + { + this.responseHandlers.put(internalActionId, responseEventHandler); + } + + // ...and event handler. + synchronized (this.responseEventHandlers) + { + this.responseEventHandlers.put(internalActionId, + responseEventHandler); + } + + writer.sendAction(action); + + // let's wait to see what we get + start = System.currentTimeMillis(); + timeSpent = 0; + while (responseEvents.getResponse() == null + || !responseEvents.isComplete()) + { + try + { + Thread.sleep(timeout - timeSpent); + } + catch (InterruptedException ex) + { + } + + // still no response or not all events received and timed out? + timeSpent = System.currentTimeMillis() - start; + if ((responseEvents.getResponse() == null || !responseEvents + .isComplete()) + && timeSpent > timeout) + { + // clean up + synchronized (this.responseEventHandlers) + { + this.responseEventHandlers.remove(internalActionId); + } + + throw new TimeoutException( + "Timeout waiting for response or response events to " + + action.getAction()); + } + } + + // remove the event handler (note: the response handler is removed + // automatically when the response is received) + synchronized (this.responseEventHandlers) + { + this.responseEventHandlers.remove(internalActionId); + } + + return responseEvents; + } + /** * Creates a new unique internal action id based on the hash code of this * connection and a sequence. + * + * @see Util#addInternalActionId(String, String) + * @see Util#getInternalActionId(String) + * @see Util#stripInternalActionId(String) */ private String createInternalActionId() { @@ -505,7 +749,8 @@ public class DefaultManagerConnection im { synchronized (this.eventHandlers) { - if (! this.eventHandlers.contains(eventHandler)) + // only add it if its not already there + if (!this.eventHandlers.contains(eventHandler)) { this.eventHandlers.add(eventHandler); } @@ -533,14 +778,14 @@ public class DefaultManagerConnection im return asteriskServer; } - /* Callbacks for ManagerReaderImpl */ + /* Implementation of Dispatcher: callbacks for ManagerReader */ /** * This method is called by the reader whenever a {@link ManagerResponse} is * received. The response is dispatched to the associated * {@link ManagerResponseHandler}. * - * @param response the resonse received by the reader + * @param response the response received by the reader * @see ManagerReader */ public void dispatchResponse(ManagerResponse response) @@ -549,6 +794,7 @@ public class DefaultManagerConnection im String internalActionId; ManagerResponseHandler responseHandler; + // shouldn't happen if (response == null) { logger.error("Unable to dispatch null response"); @@ -580,17 +826,17 @@ public class DefaultManagerConnection im } else { - logger - .warn("No response handler registered for internalActionId '" - + internalActionId + "'"); + // when using the async sendAction it's ok not to register a + // callback so if we don't find a response handler thats ok + logger.debug("No response handler registered for " + + "internalActionId '" + internalActionId + "'"); } } } else { - logger - .error("Unable to retrieve internalActionId from response: asterisk sent actionId '" - + actionId + "':\n" + response); + logger.error("Unable to retrieve internalActionId from response: " + + "actionId '" + actionId + "':\n" + response); } if (responseHandler != null) @@ -601,13 +847,10 @@ public class DefaultManagerConnection im } catch (Exception e) { - logger.warn("Exception calling responseHandler", e); + logger.warn("Exception calling responseHandler " + + responseHandler.getClass().getName(), e); } } - else - { - logger.info("responseHandler not found"); - } } /** @@ -621,14 +864,53 @@ public class DefaultManagerConnection im */ public void dispatchEvent(ManagerEvent event) { + // shouldn't happen if (event == null) { logger.error("Unable to dispatch null event"); return; } - logger.debug("Dispatching event:\n" + event); + logger.debug("Dispatching event:\n" + event.toString()); + + // dispatch ResponseEvents to the appropriate responseEventHandler + if (event instanceof ResponseEvent) + { + ResponseEvent responseEvent; + String internalActionId; + + responseEvent = (ResponseEvent) event; + internalActionId = responseEvent.getInternalActionId(); + if (internalActionId != null) + { + synchronized (responseEventHandlers) + { + ManagerEventHandler eventHandler; + + eventHandler = (ManagerEventHandler) responseEventHandlers + .get(internalActionId); + if (eventHandler != null) + { + try + { + eventHandler.handleEvent(event); + } + catch (Exception e) + { + logger.warn("Exception calling eventHandler " + + eventHandler.getClass().getName(), e); + } + } + } + } + else + { + logger.error("Unable to handle ResponseEvent without " + + "internalActionId:\n" + responseEvent); + } + } + // dispatch to eventHandlers registered by users synchronized (eventHandlers) { Iterator i = eventHandlers.iterator(); @@ -643,17 +925,23 @@ public class DefaultManagerConnection im } catch (Exception e) { - logger.warn("Exception calling eventHandler", e); + logger.warn("Exception calling eventHandler " + + eventHandler.getClass().getName(), e); } } } + // process special events if (event instanceof ConnectEvent) { - setProtocolIdentifier(((ConnectEvent) event) - .getProtocolIdentifier()); + ConnectEvent connectEvent; + String protocolIdentifier; + + connectEvent = (ConnectEvent) event; + protocolIdentifier = connectEvent.getProtocolIdentifier(); + setProtocolIdentifier(protocolIdentifier); } - if (event instanceof DisconnectEvent) + else if (event instanceof DisconnectEvent) { reconnect(); } @@ -664,7 +952,7 @@ public class DefaultManagerConnection im * reader. Having received a correct protocol identifier is the precodition * for logging in. * - * @param protocolIdentifier the protocol version used by the asterisk + * @param protocolIdentifier the protocol version used by the Asterisk * server. */ private void setProtocolIdentifier(final String protocolIdentifier) @@ -673,14 +961,12 @@ public class DefaultManagerConnection im if (!"Asterisk Call Manager/1.0".equals(protocolIdentifier)) { - logger - .warn("Unsupported protocol version '" - + protocolIdentifier - + "'. This library has only been tested with version 1.0 of the asterisk " - + "call manager protocol. Use at your own risk!"); + logger.warn("Unsupported protocol version '" + protocolIdentifier + + "'. Use at your own risk."); } this.protocolIdentifier = protocolIdentifier; + } /** @@ -722,7 +1008,7 @@ public class DefaultManagerConnection im } catch (InterruptedException e1) { - // it's ok to awake us + // it's ok to wake us } try @@ -744,14 +1030,16 @@ public class DefaultManagerConnection im } else { - logger.error("Unable to log in after reconnect. Giving up."); + logger.error("Unable to log in after reconnect. " + + "Giving up."); this.keepAlive = false; } } catch (TimeoutException e1) { // shouldn't happen - logger.error("TimeoutException while trying to log in after reconnect."); + logger.error("TimeoutException while trying to log in " + + "after reconnect."); synchronized (this) { socket.close(); @@ -811,15 +1099,101 @@ public class DefaultManagerConnection im */ private static final long serialVersionUID = 2926598671855316803L; private ResponseHandlerResult result; + private final Thread thread; - public DefaultResponseHandler(ResponseHandlerResult result) + /** + * Creates a new instance. + * + * @param result the result to store the response in + * @param thread the thread to interrupt when the response has been + * received + */ + public DefaultResponseHandler(ResponseHandlerResult result, + Thread thread) { this.result = result; + this.thread = thread; } public void handleResponse(ManagerResponse response) { - this.result.setResponse(response); + result.setResponse(response); + thread.interrupt(); + } + } + + /** + * A combinded event and response handler that adds received events and the + * response to a ResponseEvents object. + */ + private class ResponseEventHandler + implements + ManagerEventHandler, + ManagerResponseHandler, + Serializable + { + /** + * Serializable version identifier + */ + private static final long serialVersionUID = 2926598671855316803L; + private final ResponseEventsImpl events; + private final Class actionCompleteEventClass; + private final Thread thread; + + /** + * Creates a new instance. + * + * @param events the ResponseEventsImpl to store the events in + * @param actionCompleteEventClass the type of event that indicates that + * all events have been received + * @param thread the thread to interrupt when the + * actionCompleteEventClass has been received + */ + public ResponseEventHandler(ResponseEventsImpl events, + Class actionCompleteEventClass, Thread thread) + { + this.events = events; + this.actionCompleteEventClass = actionCompleteEventClass; + this.thread = thread; + } + + public void handleEvent(ManagerEvent event) + { + // should always be a ResponseEvent, anyway... + if (event instanceof ResponseEvent) + { + ResponseEvent responseEvent; + + responseEvent = (ResponseEvent) event; + events.addEvent(responseEvent); + } + + // finished? + if (actionCompleteEventClass.isAssignableFrom(event.getClass())) + { + synchronized (events) + { + events.setComplete(true); + if (events.getResponse() != null) + { + thread.interrupt(); + } + } + } + } + + public void handleResponse(ManagerResponse response) + { + synchronized (events) + { + events.setRepsonse(response); + + // finished? + if (events.isComplete()) + { + thread.interrupt(); + } + } } } } Index: ManagerConnection.java =================================================================== RCS file: /cvsroot/asterisk-java/asterisk-java/src/java/net/sf/asterisk/manager/ManagerConnection.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -p -r1.9 -r1.10 --- ManagerConnection.java 16 Jul 2005 13:19:34 -0000 1.9 +++ ManagerConnection.java 16 Jul 2005 21:48:16 -0000 1.10 @@ -18,6 +18,7 @@ package net.sf.asterisk.manager; import java.io.IOException; +import net.sf.asterisk.manager.action.EventGeneratingAction; import net.sf.asterisk.manager.action.ManagerAction; import net.sf.asterisk.manager.event.ManagerEvent; import net.sf.asterisk.manager.response.ManagerResponse; @@ -45,10 +46,10 @@ public interface ManagerConnection * Asterisk allows you to send custom events via the UserEvent application. * If you choose to send such events you can extend the abstract class * UserEvent provide a name for your new event and optionally add your own - * attributes. After registering a user event type asterisk-java will handle + * attributes. After registering a user event type Asterisk-Java will handle * such events the same way it handles the internal events and inform your * registered event handlers.<br> - * Note: If you write your own asterisk applications that use asterisk's + * Note: If you write your own Asterisk applications that use Asterisk's * <code>manager_event()</code> function directly and don't use the * channel and uniqueid attributes provided by UserEvent you can also * register events that directly subclass ManagerEvent. @@ -60,7 +61,7 @@ public interface ManagerConnection void registerUserEventClass(Class userEventClass); /** - * Logs in to the asterisk server with the username and password specified + * Logs in to the Asterisk server with the username and password specified * when this connection was created. * * @throws IOException if the network connection is disrupted. @@ -78,7 +79,7 @@ public interface ManagerConnection TimeoutException; /** - * Sends a LogoffAction to the asterisk server and disconnects. + * Sends a LogoffAction to the Asterisk server and disconnects. * * @throws IOException if the network connection is disrupted. * @throws TimeoutException if no response to the logoff action is received @@ -91,59 +92,133 @@ public interface ManagerConnection * Returns the protocol identifier, i.e. a string like "Asterisk Call * Manager/1.0". * - * @return the protocol identifier of the asterisk manager interface in use + * @return the protocol identifier of the Asterisk Manager Interface in use * if it has already been received; <code>null</code> otherwise */ String getProtocolIdentifier(); /** - * Sends a ManagerAction to the asterisk manager interface and waits for the + * Sends a ManagerAction to the Asterisk server and waits for the * corresponding ManagerResponse. * - * @param action the action to send to the asterisk server - * @return the corresponding response received from the asterisk server + * @param action the action to send to the Asterisk server + * @return the corresponding response received from the Asterisk server * @throws IOException if the network connection is disrupted. - * @throws TimeoutException if no reponse is received within the default + * @throws TimeoutException if no response is received within the default * timeout period. + * @throws IllegalArgumentException if the action is <code>null</code>. + * @throws IllegalStateException if you are not connected to an Asterisk + * server. * @see #sendAction(ManagerAction, long) * @see #sendAction(ManagerAction, ManagerResponseHandler) */ ManagerResponse sendAction(ManagerAction action) throws IOException, - TimeoutException; + TimeoutException, IllegalArgumentException, IllegalStateException; /** - * Sends a ManagerAction to the asterisk manager interface and waits for the - * corresponding {@link ManagerResponse}. + * Sends a ManagerAction to the Asterisk server and waits for the + * corresponding ManagerResponse. * - * @param action the action to send to the asterisk server - * @param timeout milliseconds to wait for the reponse before throwing a + * @param action the action to send to the Asterisk server + * @param timeout milliseconds to wait for the response before throwing a * TimeoutException - * @return the corresponding response received from the asterisk server + * @return the corresponding response received from the Asterisk server * @throws IOException if the network connection is disrupted. - * @throws TimeoutException if no reponse is received within the given + * @throws TimeoutException if no response is received within the given * timeout period. + * @throws IllegalArgumentException if the action is <code>null</code>. + * @throws IllegalStateException if you are not connected to an Asterisk + * server. * @see #sendAction(ManagerAction, ManagerResponseHandler) */ ManagerResponse sendAction(ManagerAction action, long timeout) - throws IOException, TimeoutException; + throws IOException, TimeoutException, IllegalArgumentException, + IllegalStateException; /** - * Sends a ManagerAction to the asterisk manager interface and registers a - * callback handler to be called when the corresponding ManagerResponse is - * received. + * Sends a ManagerAction to the Asterisk server and registers a callback + * handler to be called when the corresponding ManagerResponse is received. * - * @param action the action to send to the asterisk server + * @param action the action to send to the Asterisk server * @param callbackHandler the callback handler to call when the response is - * received + * received or <code>null</code> if you are not interested in + * the response * @throws IOException if the network connection is disrupted. + * @throws IllegalArgumentException if the action is <code>null</code>. + * @throws IllegalStateException if you are not connected to an Asterisk + * server. */ void sendAction(ManagerAction action, ManagerResponseHandler callbackHandler) - throws IOException; + throws IOException, IllegalArgumentException, IllegalStateException; + + /** + * Sends a EventGeneratingAction to the Asterisk server and waits for the + * corresponding ManagerResponse and the ResponseEvents.<br> + * EventGeneratingActions are ManagerActions that don't return their + * response in the corresponding ManagerResponse but send a series of events + * that contain the payload.<br> + * Examples for EventGeneratingActions are the + * {@link net.sf.asterisk.manager.action.StatusAction}, the + * {@link net.sf.asterisk.manager.action.QueueAction} or the + * {@link net.sf.asterisk.manager.action.AgentsAction}. + * + * @param action the action to send to the Asterisk server + * @return a ResponseEvents that contains the corresponding response and + * response events received from the Asterisk server + * @throws IOException if the network connection is disrupted. + * @throws TimeoutException if no response or not all response events are + * received within the given timeout period. + * @throws IllegalArgumentException if the action is <code>null</code>, + * the actionCompleteEventClass property of the action is + * <code>null</code> or if actionCompleteEventClass is not a + * ResponseEvent. + * @throws IllegalStateException if you are not connected to an Asterisk + * server. + * @see EventGeneratingAction + * @see net.sf.asterisk.manager.event.ResponseEvent + * @since 0.2 + */ + ResponseEvents sendEventGeneratingAction(EventGeneratingAction action) + throws IOException, TimeoutException, IllegalArgumentException, + IllegalStateException; + + /** + * Sends a EventGeneratingAction to the Asterisk server and waits for the + * corresponding ManagerResponse and the ResponseEvents. + * EventGeneratingActions are ManagerActions that don't return their + * response in the corresponding ManagerResponse but send a series of events + * that contain the payload.<br> + * Examples for EventGeneratingActions are the + * {@link net.sf.asterisk.manager.action.StatusAction}, the + * {@link net.sf.asterisk.manager.action.QueueAction} or the + * {@link net.sf.asterisk.manager.action.AgentsAction}. + * + * @param action the action to send to the Asterisk server + * @param timeout milliseconds to wait for the response and the response + * events before throwing a TimeoutException + * @return a ResponseEvents that contains the corresponding response and + * response events received from the Asterisk server + * @throws IOException if the network connection is disrupted. + * @throws TimeoutException if no response or not all response events are + * received within the given timeout period. + * @throws IllegalArgumentException if the action is <code>null</code>, + * the actionCompleteEventClass property of the action is + * <code>null</code> or if actionCompleteEventClass is not a + * ResponseEvent. + * @throws IllegalStateException if you are not connected to an Asterisk + * server. + * @see EventGeneratingAction + * @see net.sf.asterisk.manager.event.ResponseEvent + * @since 0.2 + */ + ResponseEvents sendEventGeneratingAction(EventGeneratingAction action, + long timeout) throws IOException, TimeoutException, + IllegalArgumentException, IllegalStateException; /** * Registers an event handler to be called whenever an * {@link net.sf.asterisk.manager.event.ManagerEvent} is receiced from the - * asterisk server.<br> + * Asterisk server.<br> * Event handlers are notified about new events in the same order as they * were registered via addEventHandler. * |