Thread: [Asterisk-java-users] Newbie question
Brought to you by:
srt
From: Fabio E. <fab...@gm...> - 2006-03-15 18:48:07
|
Hello, I'm want to make a softphone with asterisk-java. Is this possible? Reading the documentation asterisk-java I can't understand if he is only=20 for manager the server or to use as client (note: i'm brazilian and my=20 english isn't so good) I have difficult to understand what is the channel, context and the=20 extension for example. Using the asterisk-java I can connect to asterisk but i have no idea how=20 to dial for anyone. Thanks F=E1bio Esp=F3sito |
From: Alberto L. <lop...@gm...> - 2009-02-20 18:16:50
|
Hi to all, i´m a complete asteriskJava noob, so please bare with me, i need to configure the defaultAgiServer to allow a poolSize greater than 50 concurrent agi scripts, the tutorial states that this can be done adding a classpath to a fastagi.properties file, ¿can somebody tell me how this is done?, a step by step instruction will be really appreciated :). Thanks A. Andere |
From: Jon H. <jo...@as...> - 2006-03-15 20:12:13
|
Fabio, If you're interested in making a softphone that can use asterisk-java, you'll first want to read up on sip, iax, or both. While sending requests to call people via iax or sip is what most people do, read up on the asterisk manager. With it, asterisk-java can send originate requests to call people, and also you'll be able to bridge people elsewhere mid-call using the asterisk manager and asterisk-java. Hopefully after you read up on sip and/or iax, it will help you understand how you should go about creating a softphone. -Jon Fabio Esposito wrote: > Hello, > > I'm want to make a softphone with asterisk-java. Is this possible? > Reading the documentation asterisk-java I can't understand if he is > only for manager the server or to use as client (note: i'm brazilian > and my english isn't so good) > > I have difficult to understand what is the channel, context and the > extension for example. > > Using the asterisk-java I can connect to asterisk but i have no idea > how to dial for anyone. > > Thanks > Fábio Espósito > > > > > > > > ------------------------------------------------------- > This SF.Net email is sponsored by xPML, a groundbreaking scripting > language > that extends applications into web and mobile media. Attend the live > webcast > and join the prime developer group breaking into this new coding > territory! > http://sel.as-us.falkag.net/sel?cmd=k&kid0944&bid$1720&dat1642 > _______________________________________________ > Asterisk-java-users mailing list > Ast...@li... > https://lists.sourceforge.net/lists/listinfo/asterisk-java-users |
From: Ron S. <rse...@ha...> - 2006-03-16 04:21:55
|
> > Using the asterisk-java I can connect to asterisk but i have no idea how > to dial for anyone. > Asterisk-java is for controlling asterisk, not for actually being a phone. -Ron |
From: Brett S. <bs...@no...> - 2006-03-16 12:44:09
|
I've been trying to determine a reliable method for matching events to an originate. I've experimented with the DefaultManagerConnection Call method, but I'm not convinced its reliable (in fact I'm pretty certain it isn't). As such I've developed a patch for the DefaultMangerConnection sendAction method. The patch basically sets the ActionID of the response object, currently it is left as null. By setting the actionid, and using the Async mode of sendAction which generates an OriginateSuccessEvent (or failure) I have been able to retrieve the uniqueid associated with the originate and then use that to match subsequent events. Please find the attached update to DefaultManagerConnection. I have also submitted a sample class from AsterFax which demonstrates the technique described. I believe the patch is non-invasive. Regards, Brett. |
From: Stefan R. <sr...@re...> - 2006-03-16 22:38:52
Attachments:
signature.asc
|
Hi Brett, i am not sure I got what your intention ist. The internal action id should be completely invisible from user's code. As its name implies it is internal to Asterisk-Java. Therefore it is set in ActionWriter and removed in EventBuilder. If your code must make use of the action id itself you can just set your own action id and will get that back (AJ adds its internal action id and strips it from responses and event before passing them to your app resulting in your app always seeing your action id). Regarding the concrete task (originat) a better solution is probably anyway sth like this: OriginateAction originateAction =3D new OriginateAction(); originateAction.setChannel("SIP/1310"); originateAction.setExten("1399"); originateAction.setContext("from-local"); originateAction.setPriority(new Integer(1)); originateAction.setTimeout(new Long(10000)); originateAction.setAsync(Boolean.TRUE); ResponseEvents responseEvents =3D c.sendEventGeneratingAction(originateAction, 30000); for (ManagerEvent event : responseEvents.getEvents()) { if (event instanceof OriginateSuccessEvent) { OriginateSuccessEvent success =3D (OriginateSuccessEvent)= event; System.out.println("Originate was successful: uniqueId " = + success.getUniqueId()); } else if (event instanceof OriginateFailureEvent) { System.out.println("Originate failed"); } } =3DStefan Brett Sutton wrote: > I've been trying to determine a reliable method for matching events to > an originate. > I've experimented with the DefaultManagerConnection Call method, but I'= m > not convinced its reliable (in fact I'm pretty certain it isn't). >=20 > As such I've developed a patch for the DefaultMangerConnection > sendAction method. > The patch basically sets the ActionID of the response object, currently= > it is left as null. > By setting the actionid, and using the Async mode of sendAction which > generates an OriginateSuccessEvent (or failure) I have been able to > retrieve the uniqueid associated with the originate and then use that t= o > match subsequent events. >=20 > Please find the attached update to DefaultManagerConnection. I have als= o > submitted a sample class from AsterFax which demonstrates the technique= > described. >=20 > I believe the patch is non-invasive. >=20 > Regards, > Brett. >=20 >=20 > -----------------------------------------------------------------------= - >=20 > /* > * 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 imp= lied. > * See the License for the specific language governing permissions and= > * limitations under the License. > * > */ > package org.asteriskjava.manager; >=20 > import java.io.IOException; > import java.io.Serializable; > import java.security.MessageDigest; > import java.security.NoSuchAlgorithmException; > import java.util.ArrayList; > import java.util.HashMap; > import java.util.List; > import java.util.Map; >=20 > import org.asteriskjava.AsteriskVersion; > import org.asteriskjava.io.SocketConnectionFacade; > import org.asteriskjava.io.impl.SocketConnectionFacadeImpl; > import org.asteriskjava.manager.action.ChallengeAction; > import org.asteriskjava.manager.action.CommandAction; > import org.asteriskjava.manager.action.EventGeneratingAction; > import org.asteriskjava.manager.action.LoginAction; > import org.asteriskjava.manager.action.LogoffAction; > import org.asteriskjava.manager.action.ManagerAction; > import org.asteriskjava.manager.event.ConnectEvent; > import org.asteriskjava.manager.event.DisconnectEvent; > import org.asteriskjava.manager.event.ManagerEvent; > import org.asteriskjava.manager.event.ResponseEvent; > import org.asteriskjava.manager.impl.ManagerReaderImpl; > import org.asteriskjava.manager.impl.ManagerWriterImpl; > import org.asteriskjava.manager.impl.ResponseEventsImpl; > import org.asteriskjava.manager.impl.Util; > import org.asteriskjava.manager.response.ChallengeResponse; > import org.asteriskjava.manager.response.CommandResponse; > import org.asteriskjava.manager.response.ManagerError; > import org.asteriskjava.manager.response.ManagerResponse; > import org.asteriskjava.util.Log; > import org.asteriskjava.util.LogFactory; >=20 >=20 > /** > * Default implemention of the ManagerConnection interface.<br> > * Generelly avoid direct use of this class. Use the ManagerConnectionF= actory to > * obtain a ManagerConnection instead.<br> > * When using a dependency injection framework like Spring direct usage= for > * wiring up beans that require a ManagerConnection property is fine th= ough.<br> > * Note that the DefaultManagerConnection will create one new Thread > * for reading data from Asterisk on the first call to on of the login(= ) > * methods. > *=20 > * @see org.asteriskjava.manager.ManagerConnectionFactory > * @author srt > * @version $Id: DefaultManagerConnection.java,v 1.36 2006/01/10 23:09:= 11 srt Exp $ > */ > public class DefaultManagerConnection implements ManagerConnection, Dis= patcher > { > /** > * Instance logger. > */ > private final Log logger =3D LogFactory.getLog(getClass()); >=20 > /** > * Used to construct the internalActionId. > */ > private long actionIdCount =3D 0; >=20 > /* Config attributes */ > /** > * The Asterisk server to connect to. > */ > private AsteriskServer asteriskServer; >=20 > /** > * The username to use for login as defined in Asterisk's > * <code>manager.conf</code>. > */ > protected String username; >=20 > /** > * The password to use for login as defined in Asterisk's > * <code>manager.conf</code>. > */ > protected String password; >=20 > /** > * The default timeout to wait for a ManagerResponse after sending = a > * ManagerAction. > */ > private long defaultResponseTimeout =3D 2000; >=20 > /** > * The default timeout to wait for the last ResponseEvent after sen= ding an > * EventGeneratingAction. > */ > private long defaultEventTimeout =3D 5000; >=20 > /** > * The timeout to use when connecting the the Asterisk server. > */ > private int socketTimeout =3D 0; >=20 > /** > * The time the calling thread is sleeping between checking if a re= ponse or > * the protocol identifer has been received. > */ > private long sleepTime =3D 50; >=20 > /** > * Should we continue to reconnect after an authentication failure?= > */ > private boolean keepAliveAfterAuthenticationFailure =3D false; >=20 > /** > * The socket to use for TCP/IP communication with Asterisk. > */ > private SocketConnectionFacade socket; >=20 > /** > * The thread that runs the reader. > */ > private Thread readerThread; >=20 > /** > * The reader to use to receive events and responses from asterisk.= > */ > private ManagerReader reader; >=20 > /** > * The writer to use to send actions to asterisk. > */ > private ManagerWriter writer; >=20 > /** > * The protocol identifer Asterisk sends on connect. > */ > private String protocolIdentifier; > =20 > /** > * The version of the Asterisk server we are connected to. > */ > private AsteriskVersion version; >=20 > /** > * Contains the registered handlers that process the ManagerRespons= es.<br> > * Key is the internalActionId of the Action sent and value the > * corresponding ResponseHandler. > */ > private final Map<String, ManagerResponseHandler> responseHandlers;= >=20 > /** > * 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<String, ManagerEventHandler> responseEventHandler= s; >=20 > /** > * Contains the event handlers that users registered. > */ > private final List<ManagerEventHandler> eventHandlers; >=20 > /** > * 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 failu= re when > * keepAliveAfterAuthenticationFailure is <code>false</code>. > */ > protected boolean keepAlive =3D false; >=20 > /** > * Creates a new instance. > */ > public DefaultManagerConnection() > { > this.asteriskServer =3D new AsteriskServer(); >=20 > this.responseHandlers =3D new HashMap<String, ManagerResponseHa= ndler>(); > this.responseEventHandlers =3D new HashMap<String, ManagerEvent= Handler>(); > this.eventHandlers =3D new ArrayList<ManagerEventHandler>(); > } >=20 > /** > * Creates a new instance with the given connection parameters. > *=20 > * @param hostname the hostname of the Asterisk server to connect t= o. > * @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 u= sername, > String password) > { > this(); >=20 > setHostname(hostname); > setPort(port); > setUsername(username); > setPassword(password); > } >=20 > // the following two methods can be overriden when running test cas= es to > // return a mock object > protected ManagerReader createReader(Dispatcher dispatcher, > AsteriskServer server) > { > return new ManagerReaderImpl(dispatcher, server); > } >=20 > protected ManagerWriter createWriter() > { > return new ManagerWriterImpl(); > } >=20 > /** > * Sets the hostname of the asterisk server to connect to.<br> > * Default is <code>localhost</code>. > *=20 > * @param hostname the hostname to connect to > */ > public void setHostname(String hostname) > { > this.asteriskServer.setHostname(hostname); > } >=20 > /** > * Sets the port to use to connect to the asterisk server. This is = the port > * specified in asterisk's <code>manager.conf</code> file.<br> > * Default is 5038. > *=20 > * @param port the port to connect to > */ > public void setPort(int port) > { > this.asteriskServer.setPort(port); > } >=20 > /** > * Sets the username to use to connect to the asterisk server. This= is the > * username specified in asterisk's <code>manager.conf</code> file.= > *=20 > * @param username the username to use for login > */ > public void setUsername(String username) > { > this.username =3D username; > } >=20 > /** > * Sets the password to use to connect to the asterisk server. This= is the > * password specified in Asterisk's <code>manager.conf</code> file.= > *=20 > * @param password the password to use for login > */ > public void setPassword(String password) > { > this.password =3D password; > } >=20 > /** > * Sets the time in milliseconds the synchronous sendAction methods= > * {@link #sendAction(ManagerAction)} will wait for a response befo= re > * throwing a TimeoutException.<br> > * Default is 2000. > *=20 > * @param defaultTimeout default timeout in milliseconds > * @deprecated use {@link #setDefaultResponseTimeout(long)} instead= > */ > public void setDefaultTimeout(long defaultTimeout) > { > setDefaultResponseTimeout(defaultTimeout); > } >=20 > /** > * Sets the time in milliseconds the synchronous method > * {@link #sendAction(ManagerAction)} will wait for a response befo= re > * throwing a TimeoutException.<br> > * Default is 2000. > *=20 > * @param defaultResponseTimeout default response timeout in millis= econds > * @since 0.2 > */ > public void setDefaultResponseTimeout(long defaultResponseTimeout) > { > this.defaultResponseTimeout =3D defaultResponseTimeout; > } >=20 > /** > * Sets the time in milliseconds the synchronous method > * {@link #sendEventGeneratingAction(EventGeneratingAction)} will w= ait for a > * response and the last response event before throwing a TimeoutEx= ception.<br> > * Default is 5000. > *=20 > * @param defaultEventTimeout default event timeout in milliseconds= > * @since 0.2 > */ > public void setDefaultEventTimeout(long defaultEventTimeout) > { > this.defaultEventTimeout =3D defaultEventTimeout; > } >=20 > /** > * 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= =2E<br> > * The sleepTime attribute is also used when checking for the proto= col > * identifer.<br> > * Default is 50. > *=20 > * @param sleepTime time in milliseconds to sleep between two check= s for the > * arrival of a response or the protocol identifier > * @deprecated this has been replaced by an interrupt based respons= e > * checking approach. > */ > public void setSleepTime(long sleepTime) > { > this.sleepTime =3D sleepTime; > } >=20 > /** > * Set to <code>true</code> to try reconnecting to ther asterisk se= rve > * even if the reconnection attempt threw an AuthenticationFailedEx= ception.<br> > * Default is <code>false</code>. > */ > public void setKeepAliveAfterAuthenticationFailure( > boolean keepAliveAfterAuthenticationFailure) > { > this.keepAliveAfterAuthenticationFailure =3D keepAliveAfterAuth= enticationFailure; > } >=20 > /* Implementation of ManagerConnection interface */ >=20 > public void registerUserEventClass(Class userEventClass) > { > if (reader =3D=3D null) > { > reader =3D createReader(this, asteriskServer); > } >=20 > reader.registerEventClass(userEventClass); > } >=20 > public void setSocketTimeout(int socketTimeout) > { > this.socketTimeout =3D socketTimeout; > } >=20 > public void login() throws IOException, AuthenticationFailedExcepti= on, > TimeoutException > { > login(defaultResponseTimeout, null); > } >=20 > public void login(String events) throws IOException, Authentication= FailedException, > TimeoutException > { > login(defaultResponseTimeout, events); > } >=20 > /** > * Does the real login, following the steps outlined below.<br> > * <ol> > * <li>Connects to the asterisk server by calling {@link #connect()= } if not > * already connected > * <li>Waits until the protocol identifier is received. This is che= cked > * every {@link #sleepTime} ms but not longer than timeout ms in to= tal. > * <li>Sends a {@link ChallengeAction} requesting a challenge for a= uthType > * MD5. > * <li>When the {@link ChallengeResponse} is received a {@link Logi= nAction} > * is sent using the calculated key (MD5 hash of the password appen= ded to > * the received challenge). > * </ol> > *=20 > * @param timeout the maximum time to wait for the protocol identif= ier (in > * ms) > * @param events the event mask. Set to "on" if all events should b= e send, > * "off" if not events should be sent or a combination o= f > * "system", "call" and "log" (separated by ',') to spec= ify what > * kind of events should be sent. > * @throws AuthenticationFailedException if username or password ar= e > * incorrect and the login action returns an error or i= f the MD5 > * hash cannot be computed. The connection is closed in= this > * case. > * @throws TimeoutException if a timeout occurs either while waitin= g for the > * protocol identifier or when sending the challenge or= login > * action. The connection is closed in this case. > */ > private void login(long timeout, String events) throws IOException,= > AuthenticationFailedException, TimeoutException > { > long start; > long timeSpent; > ChallengeAction challengeAction; > ChallengeResponse challengeResponse; > String challenge; > String key; > LoginAction loginAction; > ManagerResponse loginResponse; >=20 > if (socket =3D=3D null) > { > connect(); > } >=20 > start =3D System.currentTimeMillis(); > while (getProtocolIdentifier() =3D=3D null) > { > try > { > Thread.sleep(sleepTime); > } > catch (InterruptedException e) > { > } >=20 > timeSpent =3D System.currentTimeMillis() - start; > if (getProtocolIdentifier() =3D=3D null && timeSpent > time= out) > { > disconnect(); > throw new TimeoutException( > "Timeout waiting for protocol identifier"); > } > } >=20 > challengeAction =3D new ChallengeAction("MD5"); > challengeResponse =3D (ChallengeResponse) sendAction(challengeA= ction); >=20 > challenge =3D challengeResponse.getChallenge(); >=20 > try > { > MessageDigest md; >=20 > md =3D MessageDigest.getInstance("MD5"); > if (challenge !=3D null) > { > md.update(challenge.getBytes()); > } > if (password !=3D null) > { > md.update(password.getBytes()); > } > key =3D Util.toHexString(md.digest()); > } > catch (NoSuchAlgorithmException ex) > { > disconnect(); > throw new AuthenticationFailedException( > "Unable to create login key using MD5 Message Diges= t", ex); > } >=20 > loginAction =3D new LoginAction(username, "MD5", key, events); > loginResponse =3D sendAction(loginAction); > if (loginResponse instanceof ManagerError) > { > disconnect(); > throw new AuthenticationFailedException(loginResponse.getMe= ssage()); > } >=20 > // successfully logged in so assure that we keep trying to reco= nnect > // when disconnected > this.keepAlive =3D true; >=20 > logger.info("Successfully logged in"); > =20 > this.version =3D determineVersion(); > this.writer.setTargetVersion(version); > =20 > logger.info("Determined Asterisk version: " + version); > } > =20 > protected AsteriskVersion determineVersion() throws IOException, Ti= meoutException > { > ManagerResponse showVersionFilesResponse; >=20 > // increase timeout as output is quite large > showVersionFilesResponse =3D sendAction(new CommandAction("show= version files pbx.c"),=20 > defaultResponseTimeout * 2); > if (showVersionFilesResponse instanceof CommandResponse) > { > List showVersionFilesResult; > =20 > showVersionFilesResult =3D ((CommandResponse) showVersionFi= lesResponse).getResult(); > if (showVersionFilesResult !=3D null && showVersionFilesRes= ult.size() > 0) > { > String line1; > =20 > line1 =3D (String) showVersionFilesResult.get(0);=20 > if (line1 !=3D null && line1.startsWith("File")) > { > return AsteriskVersion.ASTERISK_1_2; > } > } > } > =20 > return AsteriskVersion.ASTERISK_1_0; > } >=20 > protected synchronized void connect() throws IOException > { > logger.info("Connecting to " + asteriskServer.getHostname() + "= port " > + asteriskServer.getPort()); >=20 > if (this.reader =3D=3D null) > { > this.reader =3D createReader(this, asteriskServer); > } >=20 > if (this.writer =3D=3D null) > { > this.writer =3D createWriter(); > } >=20 > this.socket =3D createSocket(); >=20 > this.reader.setSocket(socket); > this.readerThread =3D new Thread(reader, "ManagerReader"); > this.readerThread.setDaemon(true); > this.readerThread.start(); >=20 > this.writer.setSocket(socket); > } >=20 > protected SocketConnectionFacade createSocket() throws IOException > { > return new SocketConnectionFacadeImpl(asteriskServer.getHostnam= e(), > asteriskServer.getPort(), socketTimeout); > } >=20 > /** > * Returns <code>true</code> if there is a socket connection to the= > * asterisk server, <code>false</code> otherwise. > *=20 > * @return <code>true</code> if there is a socket connection to the= > * asterisk server, <code>false</code> otherwise. > */ > public synchronized boolean isConnected() > { > return socket !=3D null && socket.isConnected(); // JDK 1.4 > // return socket !=3D null; > } >=20 > /** > * Sends a {@link LogoffAction} and disconnects from the server. > */ > public synchronized void logoff() throws IOException, TimeoutExcept= ion > { > LogoffAction logoffAction; >=20 > // stop reconnecting when we got disconnected > this.keepAlive =3D false; >=20 > logoffAction =3D new LogoffAction(); >=20 > if (socket !=3D null) > { > sendAction(logoffAction); > disconnect(); > } > } >=20 > /** > * Closes the socket connection. > */ > private synchronized void disconnect() > { > if (this.socket !=3D null) > { > logger.info("Closing socket."); > try > { > this.socket.close(); > } > catch (IOException ex) > { > logger.warn("Unable to close socket: " + ex.getMessage(= )); > } > this.socket =3D null; > } > } >=20 > public ManagerResponse sendAction(ManagerAction action) throws IOEx= ception, > TimeoutException, IllegalArgumentException, IllegalStateExc= eption > { > return sendAction(action, defaultResponseTimeout); > } >=20 > public ManagerResponse sendAction(ManagerAction action, long timeou= t) > throws IOException, TimeoutException, IllegalArgumentExcept= ion, > IllegalStateException > { > ResponseHandlerResult result; > ManagerResponseHandler callbackHandler; >=20 > result =3D new ResponseHandlerResult(); > callbackHandler =3D new DefaultResponseHandler(result); >=20 > synchronized (result) > { > sendAction(action, callbackHandler); > try > { > result.wait(timeout); > } > catch (InterruptedException ex) > { > //TODO fix logging > System.err.println("Interrupted!"); > } > } > =20 > // still no response? > if (result.getResponse() =3D=3D null) > { > throw new TimeoutException("Timeout waiting for response to= " > + action.getAction()); > } >=20 > result.getResponse().setActionId(action.getActionId()); > return result.getResponse(); > } >=20 > public void sendAction(ManagerAction action, > ManagerResponseHandler callbackHandler) throws IOException,= > IllegalArgumentException, IllegalStateException > { > String internalActionId; >=20 > if (action =3D=3D null) > { > throw new IllegalArgumentException( > "Unable to send action: action is null."); > } >=20 > if (socket =3D=3D null) > { > throw new IllegalStateException("Unable to send " > + action.getAction() + " action: not connected."); > } >=20 > internalActionId =3D createInternalActionId(); >=20 > // if the callbackHandler is null the user is obviously not int= erested > // in the response, thats fine. > if (callbackHandler !=3D null) > { > synchronized (this.responseHandlers) > { > this.responseHandlers.put(internalActionId, callbackHan= dler); > } > } >=20 > action.setActionId(internalActionId); > writer.sendAction(action, internalActionId); > } >=20 > public ResponseEvents sendEventGeneratingAction(EventGeneratingActi= on action) > throws IOException, EventTimeoutException, > IllegalArgumentException, IllegalStateException > { > return sendEventGeneratingAction(action, defaultEventTimeout); > } >=20 > public ResponseEvents sendEventGeneratingAction( > EventGeneratingAction action, long timeout) throws IOExcept= ion, > EventTimeoutException, IllegalArgumentException, > IllegalStateException > { > ResponseEventsImpl responseEvents; > ResponseEventHandler responseEventHandler; > String internalActionId; >=20 > if (action =3D=3D null) > { > throw new IllegalArgumentException( > "Unable to send action: action is null."); > } > else if (action.getActionCompleteEventClass() =3D=3D 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."); > } >=20 > if (socket =3D=3D null) > { > throw new IllegalStateException("Unable to send " > + action.getAction() + " action: not connected."); > } >=20 > responseEvents =3D new ResponseEventsImpl(); > responseEventHandler =3D new ResponseEventHandler(responseEvent= s, action > .getActionCompleteEventClass()); >=20 > internalActionId =3D createInternalActionId(); >=20 > // register response handler... > synchronized (this.responseHandlers) > { > this.responseHandlers.put(internalActionId, responseEventHa= ndler); > } >=20 > // ...and event handler. > synchronized (this.responseEventHandlers) > { > this.responseEventHandlers.put(internalActionId, > responseEventHandler); > } >=20 > synchronized (responseEvents) > { > writer.sendAction(action, internalActionId); > try > { > responseEvents.wait(timeout); > } > catch (InterruptedException ex) > { > //TODO fix logging > System.err.println("Interrupted"); > } > } >=20 > // still no response or not all events received and timed out? > if ((responseEvents.getResponse() =3D=3D null || !responseEvent= s > .isComplete())) > { > // clean up > synchronized (this.responseEventHandlers) > { > this.responseEventHandlers.remove(internalActionId); > } >=20 > throw new EventTimeoutException( > "Timeout waiting for response or response events to= " > + action.getAction(), responseEvents); > } >=20 > // remove the event handler (note: the response handler is remo= ved > // automatically when the response is received) > synchronized (this.responseEventHandlers) > { > this.responseEventHandlers.remove(internalActionId); > } >=20 > return responseEvents; > } >=20 > /** > * Creates a new unique internal action id based on the hash code o= f this > * connection and a sequence. > *=20 > * @see Util#addInternalActionId(String, String) > * @see Util#getInternalActionId(String) > * @see Util#stripInternalActionId(String) > */ > private String createInternalActionId() > { > final StringBuffer sb; >=20 > sb =3D new StringBuffer(); > sb.append(this.hashCode()); > sb.append("_"); > sb.append(this.actionIdCount++); >=20 > return sb.toString(); > } >=20 > public void addEventHandler(final ManagerEventHandler eventHandler)= > { > synchronized (this.eventHandlers) > { > // only add it if its not already there > if (!this.eventHandlers.contains(eventHandler)) > { > this.eventHandlers.add(eventHandler); > } > } > } >=20 > public void removeEventHandler(final ManagerEventHandler eventHandl= er) > { > synchronized (this.eventHandlers) > { > if (this.eventHandlers.contains(eventHandler)) > { > this.eventHandlers.remove(eventHandler); > } > } > } >=20 > public String getProtocolIdentifier() > { > return this.protocolIdentifier; > } >=20 > public AsteriskServer getAsteriskServer() > { > return asteriskServer; > } >=20 > /* Implementation of Dispatcher: callbacks for ManagerReader */ >=20 > /** > * This method is called by the reader whenever a {@link ManagerRes= ponse} is > * received. The response is dispatched to the associated > * {@link ManagerResponseHandler}. > *=20 > * @param response the response received by the reader > * @see ManagerReader > */ > public void dispatchResponse(ManagerResponse response) > { > final String actionId; > String internalActionId; > ManagerResponseHandler responseHandler; >=20 > // shouldn't happen > if (response =3D=3D null) > { > logger.error("Unable to dispatch null response"); > return; > } >=20 > actionId =3D response.getActionId(); > internalActionId =3D null; > responseHandler =3D null; >=20 > if (actionId !=3D null) > { > internalActionId =3D Util.getInternalActionId(actionId); > response.setActionId(Util.stripInternalActionId(actionId));= > } >=20 > logger.debug("Dispatching response with internalActionId '" > + internalActionId + "':\n" + response); >=20 > if (internalActionId !=3D null) > { > synchronized (this.responseHandlers) > { > responseHandler =3D (ManagerResponseHandler) this.respo= nseHandlers > .get(internalActionId); > if (responseHandler !=3D null) > { > this.responseHandlers.remove(internalActionId); > } > else > { > // when using the async sendAction it's ok not to r= egister 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 resp= onse: " > + "actionId '" + actionId + "':\n" + response); > } >=20 > if (responseHandler !=3D null) > { > try > { > responseHandler.handleResponse(response); > } > catch (RuntimeException e) > { > logger.warn("Unexpected exception in responseHandler " > + responseHandler.getClass().getName(), e); > } > } > } >=20 > /** > * This method is called by the reader whenever a ManagerEvent is r= eceived. > * The event is dispatched to all registered ManagerEventHandlers. > *=20 > * @param event the event received by the reader > * @see #addEventHandler(ManagerEventHandler) > * @see #removeEventHandler(ManagerEventHandler) > * @see ManagerReader > */ > public void dispatchEvent(ManagerEvent event) > { > // shouldn't happen > if (event =3D=3D null) > { > logger.error("Unable to dispatch null event"); > return; > } >=20 > logger.debug("Dispatching event:\n" + event.toString()); >=20 > // dispatch ResponseEvents to the appropriate responseEventHand= ler > if (event instanceof ResponseEvent) > { > ResponseEvent responseEvent; > String internalActionId; >=20 > responseEvent =3D (ResponseEvent) event; > internalActionId =3D responseEvent.getInternalActionId(); > if (internalActionId !=3D null) > { > synchronized (responseEventHandlers) > { > ManagerEventHandler eventHandler; >=20 > eventHandler =3D (ManagerEventHandler) responseEven= tHandlers > .get(internalActionId); > if (eventHandler !=3D null) > { > try > { > eventHandler.handleEvent(event); > } > catch (RuntimeException e) > { > logger.warn("Unexpected exception in eventH= andler " > + eventHandler.getClass().getName()= , e); > } > } > } > } > else > { > // ResponseEvent without internalActionId: > // this happens if the same event class is used as resp= onse event > // and as an event that is not triggered by a Manager c= ommand > // example: QueueMemberStatusEvent. > //logger.debug("ResponseEvent without " > // + "internalActionId:\n" + responseEvent); > } > } >=20 > // dispatch to eventHandlers registered by users > synchronized (eventHandlers) > { > for (ManagerEventHandler eventHandler : eventHandlers) > { > try > { > eventHandler.handleEvent(event); > } > catch (RuntimeException e) > { > logger.warn("Unexpected exception in eventHandler "= > + eventHandler.getClass().getName(), e); > } > } > } >=20 > // process special events > if (event instanceof ConnectEvent) > { > ConnectEvent connectEvent; > String protocolIdentifier; >=20 > connectEvent =3D (ConnectEvent) event; > protocolIdentifier =3D connectEvent.getProtocolIdentifier()= ; > setProtocolIdentifier(protocolIdentifier); > } > else if (event instanceof DisconnectEvent) > { > reconnect(); > } > } >=20 > /** > * This method is called when a {@link ConnectEvent} is received fr= om the > * reader. Having received a correct protocol identifier is the pre= codition > * for logging in. > *=20 > * @param protocolIdentifier the protocol version used by the Aster= isk > * server. > */ > private void setProtocolIdentifier(final String protocolIdentifier)= > { > logger.info("Connected via " + protocolIdentifier); >=20 > if (!"Asterisk Call Manager/1.0".equals(protocolIdentifier) && > !"Asterisk Call Manager/1.2".equals(protocolIdentifier)) > { > logger.warn("Unsupported protocol version '" + protocolIden= tifier > + "'. Use at your own risk."); > } >=20 > this.protocolIdentifier =3D protocolIdentifier; >=20 > } >=20 > /** > * Reconnects to the asterisk server when the connection is lost.<b= r> > * While keepAlive is <code>true</code> we will try to reconnect. > * Reconnection attempts will be stopped when the {@link #logoff()}= method > * is called or when the login after a successful reconnect results= in an > * {@link AuthenticationFailedException} suggesting that the manage= r > * credentials have changed and keepAliveAfterAuthenticationFailure= is not > * set.<br> > * This method is called when a {@link DisconnectEvent} is received= from the > * reader. > */ > private void reconnect() > { > int numTries; >=20 > // clean up at first > disconnect(); >=20 > // try to reconnect > numTries =3D 0; > while (this.keepAlive) > { > try > { > if (numTries < 10) > { > // try to reconnect quite fast for the firt 10 time= s > // this succeeds if the server has just been restar= ted > Thread.sleep(50); > } > else > { > // slow down after 10 unsuccessful attempts asuming= a > // shutdown of the server > Thread.sleep(5000); > } > } > catch (InterruptedException e1) > { > // it's ok to wake us > } >=20 > try > { > connect(); >=20 > try > { > login(); > logger.info("Successfully reconnected."); > // everything is ok again, so we leave > break; > } > catch (AuthenticationFailedException e1) > { > if (this.keepAliveAfterAuthenticationFailure) > { > logger.error("Unable to log in after reconnect.= "); > } > else > { > logger.error("Unable to log in after reconnect.= " > + "Giving up."); > this.keepAlive =3D false; > } > } > catch (TimeoutException e1) > { > // shouldn't happen > logger.error("TimeoutException while trying to log = in " > + "after reconnect."); > synchronized (this) > { > socket.close(); > } > } > } > catch (IOException e) > { > // server seems to be still down, just continue to atte= mpt > // reconnection > logger.warn("Exception while trying to reconnect: " > + e.getMessage()); > } > numTries++; > } > } >=20 > /* Helper classes */ >=20 > /** > * A simple data object to store a ManagerResult. > */ > private class ResponseHandlerResult implements Serializable > { > /** > * Serializable version identifier > */ > private static final long serialVersionUID =3D 7831097958568769= 220L; > private ManagerResponse response; >=20 > public ResponseHandlerResult() > { > } >=20 > public ManagerResponse getResponse() > { > return this.response; > } >=20 > public void setResponse(ManagerResponse response) > { > this.response =3D response; > } > } >=20 > /** > * A simple response handler that stores the received response in a= > * ResponseHandlerResult for further processing. > */ > private class DefaultResponseHandler > implements > ManagerResponseHandler, > Serializable > { > /** > * Serializable version identifier > */ > private static final long serialVersionUID =3D 2926598671855316= 803L; > private ResponseHandlerResult result; >=20 > /** > * Creates a new instance. > *=20 > * @param result the result to store the response in > */ > public DefaultResponseHandler(ResponseHandlerResult result) > { > this.result =3D result; > } >=20 > public void handleResponse(ManagerResponse response) > { > synchronized (result) > { > result.setResponse(response); > result.notify(); > } > } > } >=20 > /** > * A combinded event and response handler that adds received events= and the > * response to a ResponseEvents object. > */ > @SuppressWarnings("unchecked") > private class ResponseEventHandler > implements > ManagerEventHandler, > ManagerResponseHandler, > Serializable > { > /** > * Serializable version identifier > */ > private static final long serialVersionUID =3D 2926598671855316= 803L; > private final ResponseEventsImpl events; > private final Class actionCompleteEventClass; >=20 > /** > * Creates a new instance. > *=20 > * @param events the ResponseEventsImpl to store the events in > * @param actionCompleteEventClass the type of event that indic= ates that > * all events have been received > * @param thread the thread to interrupt when the > * actionCompleteEventClass has been received > */ > public ResponseEventHandler(ResponseEventsImpl events, > Class actionCompleteEventClass) > { > this.events =3D events; > this.actionCompleteEventClass =3D actionCompleteEventClass;= > } >=20 > public void handleEvent(ManagerEvent event) > { > synchronized (events) > { > // should always be a ResponseEvent, anyway... > if (event instanceof ResponseEvent) > { > ResponseEvent responseEvent; > =20 > responseEvent =3D (ResponseEvent) event; > events.addEvent(responseEvent); > } > =20 > // finished? > if (actionCompleteEventClass.isAssignableFrom(event.get= Class())) > { > events.setComplete(true); > // notify if action complete event and response hav= e been received > if (events.getResponse() !=3D null) > { > events.notify(); > } > } > } > } >=20 > public void handleResponse(ManagerResponse response) > { > synchronized (events) > { > events.setRepsonse(response); > if (response instanceof ManagerError) > { > events.setComplete(true); > } >=20 > // finished? > // notify if action complete event and response have be= en received > if (events.isComplete()) > { > events.notify(); > } > } > } > } > } >=20 >=20 > -----------------------------------------------------------------------= - >=20 > /* > * Copyright 2004-2006 by S. Brett Sutton. Commercial support is provid= ed by > * Asterisk I.T. http://www.asteriskit.com.au > *=20 > * The contents of this file are subject to a modified GPL Version 2 Li= cense or > * later version at your discretion. > *=20 > * The sole modification to the GPL is a limitation on use. > *=20 > * The limitation is that AsterFax (and its source components) may only= be used > * on a single Channel as defined in AsterFax.xml. The implications of = the > * limitation is that the free verions of AsterFax may only be used to = send or > * receive a single fax at a time. > *=20 > * Any copied or modified versions of the AsterFax source must retain t= his > * limitation. > *=20 > * If you wish to use multiple channels then you can purchase a commerc= ial > * license by emailing sa...@as... > *=20 > * Contributor(s): all the names of the contributors are added in the s= ource > * code where applicable. > */ > /** > * Responsible for submitting the fax to the asterix gateway for transm= ission > */ > package au.com.noojee.asterfax.outbound; >=20 > import java.io.IOException; > import java.net.ConnectException; > import java.util.Calendar; > import java.util.Date; > import java.util.HashMap; >=20 > import javax.activation.MimeTypeParseException; > import javax.mail.MessagingException; > import javax.mail.internet.InternetAddress; >=20 > import org.apache.commons.configuration.ConfigurationException; > import org.apache.log4j.Logger; > import org.asteriskjava.live.AsteriskChannel; > import org.asteriskjava.live.DefaultAsteriskManager; > import org.asteriskjava.manager.AuthenticationFailedException; > import org.asteriskjava.manager.ManagerConnection; > import org.asteriskjava.manager.ManagerConnectionFactory; > import org.asteriskjava.manager.ManagerEventHandler; > import org.asteriskjava.manager.TimeoutException; > import org.asteriskjava.manager.action.OriginateAction; > import org.asteriskjava.manager.event.DisconnectEvent; > import org.asteriskjava.manager.event.HangupEvent; > import org.asteriskjava.manager.event.ManagerEvent; > import org.asteriskjava.manager.event.OriginateFailureEvent; > import org.asteriskjava.manager.event.OriginateSuccessEvent; > import org.asteriskjava.manager.event.ReloadEvent; > import org.asteriskjava.manager.event.ShutdownEvent; > import org.asteriskjava.manager.response.ManagerError; > import org.asteriskjava.manager.response.ManagerResponse; >=20 > import au.com.noojee.asterfax.Configuration; > import au.com.noojee.asterfax.Responses; > import au.com.noojee.asterfax.SpanDSPError; > import au.com.noojee.asterfax.converter.ConversionException; >=20 > import com.lowagie.text.DocumentException; >=20 > public class SubmitFax implements ManagerEventHandler > { >=20 > static private Logger logger =3D Logger.getLogger(SubmitFax.class); > static Logger auditLogger =3D Logger.getLogger("Audit"); >=20 > static int asterFaxOriginateID =3D 1; >=20 > // If sent as an option to txfax then txfax will not actually send the= fax. > // It will just pretend to. This is usefull for testing asterfax witho= ut > // sending lost of faxes (and paying for it :) > static final String SIMULATE =3D "simulate"; >=20 > ManagerConnectionFactory factory =3D null; > private Channel channel =3D null; > Fax fax; > ManagerEvent response =3D null; > String cause =3D null; > private String actionID; > private String uniqueID; >=20 > public SubmitFax(Fax fax, Channel channel) > throws IOException, > ConfigurationException > { > this.fax =3D fax; > this.channel =3D channel; > factory =3D new ManagerConnectionFactory(Configuration.getInstance() > .getAsteriskHost(), Configuration.getInstance() > .getAsteriskUsername(), Configuration.getInstance() > .getAsteriskPassword()); >=20 > } >=20 > public void send() > throws IOException, > AuthenticationFailedException, > TimeoutException, > ConfigurationException, > MessagingException, > ClassNotFoundException, > InterruptedException, > ConversionException, > DocumentException, > IllegalArgumentException, > MimeTypeParseException > { > InternetAddress[] recipients =3D fax.getRecipients(); > for (InternetAddress address : recipients) > { >=20 > if (Fax.isPreview(address)) > { > Responses.sendPreview(fax, address); > } > else > { > boolean success =3D false; > int maxRetries =3D Configuration.getInstance().getMaxRetries(); > int retryCount =3D 0; > while (!success && retryCount < maxRetries) > { > if (retryCount !=3D 0) > logger.info("Retry (" + (retryCount + 1) > + ") transmission of: " + fax.toString()); > success =3D sendFaxAGI(address, retryCount =3D=3D maxRetries - 1);= > retryCount++; > } > } > } > } >=20 > /** > * TODO: create retry logic. > *=20 > * @param recipient > * @param reportError > * @throws ConfigurationException > * @throws MessagingException > * @throws ClassNotFoundException > * @throws IOException > * @throws InterruptedException > * @throws ConversionException > * @throws DocumentException > * @throws AuthenticationFailedException > * @throws TimeoutException > * @throws IllegalArgumentException > * @throws MimeTypeParseException > */ > synchronized boolean sendFaxAGI(InternetAddress recipient, > boolean reportError) > throws ConfigurationException, > MessagingException, > ClassNotFoundException, > IOException, > InterruptedException, > ConversionException, > DocumentException, > AuthenticationFailedException, > TimeoutException, > IllegalArgumentException, > MimeTypeParseException > { > boolean success =3D false; > ManagerConnection connection =3D null; > try > { > Date start =3D Calendar.getInstance().getTime(); > fax.setTransmissionStartTime(start); >=20 > // connect to Asterisk and log in > connection =3D getConnection(); > DefaultAsteriskManager dam =3D new DefaultAsteriskManager(connection= ); >=20 > try > { > dam.initialize(); > dam.setSkipQueues(true); > } > catch (ConnectException e) > { > throw new IllegalStateException( > "Connection to the asterisk manager api failed. Check that asteri= sk is up and configured to accept Manager API connections."); > } >=20 > OriginateAction originateAction; > ManagerResponse originateResponse; >=20 > originateAction =3D new OriginateAction(); > originateAction.setChannel(channel.getChannelName() + "/" > + Fax.getTelephoneNo(recipient)); > originateAction.setContext(channel.getContext()); > HashMap<String, String> variables =3D new HashMap<String, String>();= > // variables.put("LOCALHEADERINFO", Configuration.getInstance() > // .getCompanyName() + " " + fax.getSubject()); > Configuration config =3D Configuration.getInstance(); > variables.put("MaxRetries", "1"); > variables.put("RetryTime", new Integer(config.getRetryTime()) > .toString()); > variables > .put("WaitTime", new Long(config.getWaitTime()).toString()); >=20 > synchronized (SubmitFax.class) > { > variables.put("AsterFaxOriginateID", new Integer( > asterFaxOriginateID++).toString()); > } >=20 > // NEED to get the channels caller id (outbound cid). > AsteriskChannel astChannel =3D dam.getChannelByName(channel > .getChannelName()); > if (astChannel !=3D null) > variables > .put("REMOTESTATIONID", astChannel.getCallerIdNumber()); >=20 > String faxPath =3D fax.getTiffFile().getFile().getAbsolutePath(); > String data =3D faxPath + "|caller"; > if (config.isDebugTxFax()) > data +=3D "|debug"; >=20 > if (Configuration.getInstance().isDebugTxFaxSimulate()) > data +=3D "|" + SIMULATE; > originateAction.setApplication("txfax"); > originateAction.setData(data); > originateAction.setVariables(variables); > originateAction.setPriority(new Integer(config.getPriority())); > originateAction.setTimeout(new Long(config.getTimeOut())); > originateAction.setAsync(true); >=20 > logger.debug("Sending Action: Channel(" > + originateAction.getChannel() + ") Context(" > + originateAction.getContext() + ") Application (" > + originateAction.getApplication() + ") Data(" > + originateAction.getData() + ") Vars(" > + originateAction.getVariables() + ")"); >=20 > connection.addEventHandler(this); > // connection. > connection.registerUserEventClass(FaxTransmittedEvent.class); >=20 > originateResponse =3D connection.sendAction(originateAction, 30000);= > this.actionID =3D originateResponse.getActionId(); >=20 >=20 > // we need the "OriginateSuccess or OriginateFailure" events > logger.debug("Response:" + originateResponse + " resp:" > + originateResponse.getResponse() + "msg: " > + originateResponse.getMessage()); >=20 > if (originateResponse instanceof ManagerError) > { > if (reportError) > Responses.sendError((ManagerError) originateResponse, fax, > new InternetAddress[] > { > recipient > }); > } > else > { > // Wait for the hangup to notify us that the fax has > // been sent or an error occured > wait(); >=20 > assert response !=3D null : "response should never be null"; > if (response instanceof FaxTransmittedEvent) > { > FaxTransmittedEvent transmitted =3D (FaxTransmittedEvent) response= ; >=20 > if (transmitted.getExecResult() =3D=3D 0 > && transmitted.getTransmissionResult() =3D=3D 0) > { > logger.info("Fax transmitted successfully for: " > + fax.toString()); > success =3D true; > } > else > { > logger.warn("Transmission attempt failed. Will retry:" > + " Exec Result=3D" > + TXFaxError.valueOf(transmitted > .getExecResult()) > + " Transmission Result=3D" > + SpanDSPError.valueOf(transmitted > .getTransmissionResult()) > + fax.toString()); > if (reportError) > { > sendError(recipient, transmitted); > } > } > } > else > { > sendError(recipient, reportError); > } > } >=20 > fax.cleanUp(); >=20 > } > catch (Throwable e) > { >=20 > logger.error(e.getMessage(), e); >=20 > if (fax !=3D null) > { > try > { > Responses.sendError(e, fax, new InternetAddress[] > { > recipient > }); > } > catch (Throwable e1) > { > logger.error("Error attempting to send error response", e1); > } > } > } > finally > { >=20 > connection.removeEventHandler(this); >=20 > Date end =3D Calendar.getInstance().getTime(); > fax.setTransmissionEndTime(end); >=20 > if (success) > { > auditLogger.info("Success: " + fax.toString(recipient)); > Responses.sendArchive(fax, recipient); > Responses.sendReceipt(fax, recipient); > } > else > auditLogger.info("Failed: " + fax.toString(recipient)); >=20 > if (connection !=3D null) > connection.logoff(); > } >=20 > return success; > } >=20 > public synchronized void handleEvent(ManagerEvent event) > { > if (event instanceof OriginateSuccessEvent) > { > OriginateSuccessEvent success =3D (OriginateSuccessEvent) event; > if (this.actionID.compareToIgnoreCase(success.getActionId()) =3D=3D = 0) > { > logger > .debug("OriginateSuccessEvent received for channel(" > + success.getChannel() > + ") with the following cause: " > + success.toString()); > this.uniqueID =3D success.getUniqueId(); > } > } > else if (event instanceof OriginateFailureEvent) > { > OriginateFailureEvent failure =3D (OriginateFailureEvent) event; > if (this.actionID.compareToIgnoreCase(failure.getActionId()) =3D=3D = 0) > { > logger.debug("OriginateFailureEvent received for channel(" > + failure.getChannel() + ") with the following cause: " > + failure.toString()); >=20 > if (response =3D=3D null) > logger > .warn("Originate Falled for call to " + failure.getChannel()); > setResponse(failure); > notify(); > } > } >=20 > else if (event instanceof HangupEvent) > { > HangupEvent hangup =3D (HangupEvent) event; > if (isOurChannel(hangup.getUniqueId())) > { > logger.debug("HangupEvent received for channel(" > + hangup.getChannel() + ") with the following cause: " > + hangup.getCause() + " " + hangup.getCauseTxt()); >=20 > if (response =3D=3D null) > logger > .error("Hangup received before FaxTransmittedEvent. Please check= that you have patched TxFax."); > setResponse(hangup); > notify(); > } > } > else if (event instanceof DisconnectEvent) > { > cause =3D "AsterFax lost its connection to Asterisk."; > logger > .debug("Received unexpected DisconnectEvent while waiting for fax = hangup."); > setResponse(event); > notify(); > } > else if (event instanceof ShutdownEvent) > { > cause =3D "Asterisk Shutting down."; > logger > .warn("Received unexpected ShutdownEvent while waiting for fax han= gup."); > setResponse(event); > notify(); > } > else if (event instanceof ReloadEvent) > { > cause =3D "Asterisk Reloadinging."; > logger > .warn("Received unexpected ReloadEvent while waiting for fax hangu= p."); > setResponse(event); > notify(); > } > else if (event instanceof FaxTransmittedEvent) > { >=20 > FaxTransmittedEvent a =3D (FaxTransmittedEvent) event; > if (isOurChannel(a.getUniqueId())) > { > logger.debug("Received FaxTransmittedEvent. ExecResult=3D" > + a.getExecResult() + " TransmissionResult=3D" > + a.getTransmissionResult() + " RemoteStationID=3D" > + a.getRemoteStationID() + " Pages Transferred=3D" > + a.getPagesTransferred()); > setResponse(a); > notify(); > } > } > // else > // { > // ignore these other events. > // logger > // .debug("Received unexpected Event while waiting for fax hangup. > // event=3D" > // + event.toString()); > // } > } >=20 > private void setResponse(ManagerEvent event) > { > if (response =3D=3D null) > { > response =3D event; > } > else > { > logger.debug("Event recieved when response already set: " > + event.toString()); > } >=20 > } >=20 > boolean isOurChannel(String uniqueID) > { > assert uniqueID !=3D null : "Unique id not passed!"; > assert this.uniqueID !=3D null : "Unique id not set!"; > return (uniqueID.toLowerCase().compareToIgnore... [truncated message content] |