/** * */ package org.mobicents.servlet.sip.example; import java.io.IOException; import java.math.BigDecimal; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.annotation.Resource; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.sip.Address; import javax.servlet.sip.AuthInfo; import javax.servlet.sip.ServletTimer; import javax.servlet.sip.SipApplicationSession; import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServlet; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.SipSession; import javax.servlet.sip.SipURI; import javax.servlet.sip.TimerListener; import javax.servlet.sip.URI; import org.apache.log4j.Logger; import org.jboss.mobicents.seam.actions.OrderManager; import org.jboss.mobicents.seam.listeners.DTMFListener; import org.jboss.mobicents.seam.listeners.MediaConnectionListener; import org.jboss.mobicents.seam.util.DTMFUtils; import org.jboss.mobicents.seam.util.TTSUtils; import org.mobicents.mscontrol.MsConnection; import org.mobicents.mscontrol.MsConnectionState; import org.mobicents.mscontrol.MsLink; import org.mobicents.mscontrol.MsPeer; import org.mobicents.mscontrol.MsPeerFactory; import org.mobicents.mscontrol.MsProvider; import org.mobicents.mscontrol.MsSession; /** * Sip Servlet handling responses to call initiated due to actions made on the web shopping demo * * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A> * */ public class ShoppingSipServlet extends SipServlet implements TimerListener { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(ShoppingSipServlet.class); private static final String CONTACT_HEADER = "Contact"; @Resource SipFactory sipFactory; /** Creates a new instance of ShoppingSipServlet */ public ShoppingSipServlet() { } @Override public void init(ServletConfig servletConfig) throws ServletException { logger.info("the shopping sip servlet has been started"); super.init(servletConfig); try { InitialContext ctx = new InitialContext(); OrderManager orderManager = Util.getOrderManager(); logger.info("Reference to OrderManagerBean " + orderManager); } catch (NamingException e) { logger.error("An exception occured while retrieving the EJB OrderManager",e); } } @Override protected void doProvisionalResponse(SipServletResponse sipServletResponse) throws ServletException, IOException { logger.info("Got : " + sipServletResponse.getStatus() + " " + sipServletResponse.getMethod()); int status = sipServletResponse.getStatus(); Boolean isHelpCall = (Boolean) sipServletResponse.getSession().getAttribute("HelpCall"); if (status == SipServletResponse.SC_SESSION_PROGRESS && "INVITE".equalsIgnoreCase(sipServletResponse.getMethod()) && (isHelpCall == null || Boolean.FALSE.equals(isHelpCall))) { //creates the connection Object sdpObj = sipServletResponse.getContent(); byte[] sdpBytes = (byte[]) sdpObj; String sdp = new String(sdpBytes); logger.info("Creating the end to end media connection"); sipServletResponse.getSession().setAttribute("playAnnouncement", Boolean.FALSE); sipServletResponse.getSession().setAttribute("audioFilePath", (String)getServletContext().getAttribute("audioFilePath")); MsConnection connection = (MsConnection)sipServletResponse.getSession().getAttribute("connection"); connection.modify("$", sdp); } } protected void doHelpCallSuccessResponse(SipServletResponse resp) throws ServletException, IOException { logger.info("Got OK"); SipSession session = resp.getSession(); Boolean inviteSent = (Boolean) session.getAttribute("InviteSent"); if (inviteSent != null && inviteSent.booleanValue()) { return; } Address secondPartyAddress = (Address) resp.getSession() .getAttribute("SecondPartyAddress"); if (secondPartyAddress != null) { SipServletRequest invite = sipFactory.createRequest(resp .getApplicationSession(), "INVITE", session .getRemoteParty(), secondPartyAddress); logger.info("Found second party -- sending INVITE to " + secondPartyAddress); String contentType = resp.getContentType(); if (contentType.trim().equals("application/sdp")) { invite.setContent(resp.getContent(), "application/sdp"); } session.setAttribute("LinkedSession", invite.getSession()); invite.getSession().setAttribute("LinkedSession", session); SipServletRequest ack = resp.createAck(); invite.getSession().setAttribute("FirstPartyAck", ack); invite.getSession().setAttribute("FirstPartyContent", resp.getContent()); invite.getSession().setAttribute("HelpCall", Boolean.TRUE); invite.send(); session.setAttribute("InviteSent", Boolean.TRUE); } else { logger.info("Got OK from second party -- sending ACK"); SipServletRequest secondPartyAck = resp.createAck(); SipServletRequest firstPartyAck = (SipServletRequest) resp .getSession().getAttribute("FirstPartyAck"); // if (resp.getContentType() != null && resp.getContentType().equals("application/sdp")) { firstPartyAck.setContent(resp.getContent(), "application/sdp"); secondPartyAck.setContent(resp.getSession().getAttribute("FirstPartyContent"), "application/sdp"); // } firstPartyAck.send(); secondPartyAck.send(); } } @Override protected void doSuccessResponse(SipServletResponse sipServletResponse) throws ServletException, IOException { logger.info("Got : " + sipServletResponse.getStatus() + " " + sipServletResponse.getMethod()); int status = sipServletResponse.getStatus(); if (status == SipServletResponse.SC_OK && "INVITE".equalsIgnoreCase(sipServletResponse.getMethod())) { Boolean isHelpCall = (Boolean) sipServletResponse.getSession().getAttribute("HelpCall"); if(isHelpCall != null && Boolean.TRUE.equals(isHelpCall)) { //Handle the help call use case doHelpCallSuccessResponse(sipServletResponse); } else { //send ack SipServletRequest ackRequest = sipServletResponse.createAck(); ackRequest.send(); //creates the connection Object sdpObj = sipServletResponse.getContent(); byte[] sdpBytes = (byte[]) sdpObj; String sdp = new String(sdpBytes); String pathToAudioDirectory = (String)getServletContext().getAttribute("audioFilePath"); sipServletResponse.getSession().setAttribute("audioFilePath", pathToAudioDirectory); MsConnection connection = (MsConnection)sipServletResponse.getSession().getAttribute("connection"); if(!connection.getState().equals(MsConnectionState.OPEN)) { logger.info("Creating the end to end media connection"); sipServletResponse.getSession().setAttribute("playAnnouncement", Boolean.TRUE); connection.modify("$", sdp); } else { logger.info("Not Creating the end to end media connection, connection already opened"); MediaConnectionListener.playAnnouncement(connection, (MsLink)sipServletResponse.getSession().getAttribute("link"), sipServletResponse.getSession(), pathToAudioDirectory); } } } } @Override protected void doErrorResponse(SipServletResponse response) throws ServletException, IOException { logger.info("Got response: " + response); SipFactory sipFactory = (SipFactory) getServletContext().getAttribute(SIP_FACTORY); if(response.getStatus() == SipServletResponse.SC_UNAUTHORIZED || response.getStatus() == SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED) { // Avoid re-sending if the auth repeatedly fails. if(!"true".equals(response.getSession().getAttribute("FirstResponseRecieved"))) { SipSession sipSession = response.getSession(); sipSession.setAttribute("FirstResponseRecieved", "true"); AuthInfo authInfo = sipFactory.createAuthInfo(); authInfo.addAuthInfo( response.getStatus(), response.getChallengeRealms().next(), getServletContext().getInitParameter("caller.sip"), getServletContext().getInitParameter("caller.password")); SipServletRequest challengeRequest = response.getSession().createRequest( response.getRequest().getMethod()); challengeRequest.addAuthHeader(response, authInfo); MsConnection connection = (MsConnection) sipSession.getAttribute("connection"); if(connection != null) { String sdp = connection.getLocalDescriptor(); try { challengeRequest.setContentLength(sdp.length()); challengeRequest.setContent(sdp.getBytes(), "application/sdp"); } catch (IOException e) { logger.error("An unexpected exception occured while sending the request", e); } } logger.info("sending challenge request " + challengeRequest); challengeRequest.send(); } } else { super.doErrorResponse(response); } } @Override protected void doInfo(SipServletRequest request) throws ServletException, IOException { //sending OK SipServletResponse ok = request.createResponse(SipServletResponse.SC_OK); ok.send(); //Getting the message content String messageContent = new String( (byte[]) request.getContent()); logger.info("got INFO request with following content " + messageContent); int signalIndex = messageContent.indexOf("Signal="); //Playing file only if the DTMF session has been started if(DTMFListener.DTMF_SESSION_STARTED == (Integer) request.getSession().getAttribute("DTMFSession")) { logger.info("DTMF session in started state, parsing message content"); if(messageContent != null && messageContent.length() > 0 && signalIndex != -1) { String signal = messageContent.substring("Signal=".length(),"Signal=".length()+1).trim(); String pathToAudioDirectory = (String)getServletContext().getAttribute("audioFilePath"); logger.info("Signal received " + signal ); if(request.getSession().getAttribute("orderApproval") != null) { if(request.getSession().getAttribute("adminApproval") != null) { logger.info("customer approval in progress."); DTMFUtils.adminApproval(request.getSession(), signal, pathToAudioDirectory); } else { logger.info("customer approval in progress."); DTMFUtils.orderApproval(request.getSession(), signal, pathToAudioDirectory); } } else if(request.getSession().getAttribute("deliveryDate") != null) { DTMFUtils.updateDeliveryDate(request.getSession(), signal); } } } else { logger.info("DTMF session in stopped state, not parsing message content"); } } @Override protected void doBye(SipServletRequest request) throws ServletException, IOException { logger.info("Got bye " + request); MsConnection connection = (MsConnection)request.getSession().getAttribute("connection"); MsLink link = (MsLink)request.getSession().getAttribute("link"); SipServletResponse ok = request .createResponse(SipServletResponse.SC_OK); ok.send(); SipSession linkedSession = (SipSession) request.getSession() .getAttribute("LinkedSession"); if (linkedSession != null) { SipServletRequest bye = linkedSession.createRequest("BYE"); logger.info("Sending bye to " + linkedSession.getRemoteParty()); bye.send(); } if(connection != null) { connection.release(); } else { logger.info("connection not created"); } if(link != null) { link.release(); } else { logger.info("link not created"); } } @Override protected void doRegister(SipServletRequest req) throws ServletException, IOException { logger.info("Received register request: " + req.getTo()); Map<String, String> users = (Map<String, String>) getServletContext().getAttribute("registeredUsersMap"); int response = SipServletResponse.SC_OK; SipServletResponse resp = req.createResponse(response); Address address = req.getAddressHeader(CONTACT_HEADER); String fromURI = req.getFrom().getURI().toString(); int expires = address.getExpires(); if(expires < 0) { expires = req.getExpires(); } if(expires == 0) { users.remove(fromURI); logger.info("User " + fromURI + " unregistered"); } else { resp.setAddressHeader(CONTACT_HEADER, address); users.put(fromURI, address.getURI().toString()); //updating the default contact address for the admin String adminAddress = (String) getServletContext().getAttribute("admin.sip"); if(fromURI.equalsIgnoreCase(adminAddress)) { getServletContext().setAttribute("admin.sip.default.contact", address.getURI().toString()); } logger.info("User " + fromURI + " registered this contact address " + address + " with an Expire time of " + expires); } resp.send(); } /* * (non-Javadoc) * @see javax.servlet.sip.TimerListener#timeout(javax.servlet.sip.ServletTimer) */ public void timeout(ServletTimer timer) { SipApplicationSession sipApplicationSession = timer.getApplicationSession(); Map<String, Object> attributes = (Map<String, Object>)timer.getInfo(); try { String callerAddress = (String)attributes.get("caller"); String callerDomain = (String)attributes.get("callerDomain"); SipURI fromURI = sipFactory.createSipURI(callerAddress, callerDomain); Address fromAddress = sipFactory.createAddress(fromURI); String customerName = (String) attributes.get("customerName"); BigDecimal amount = (BigDecimal) attributes.get("amountOrder"); String customerPhone = (String) attributes.get("customerPhone"); String customerContact = (String) attributes.get("customerContact"); if(attributes.get("adminApproval") != null) { logger.info("preparing speech for admin approval"); customerContact = (String) attributes.get("adminContactAddress"); //TTS file creation StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(customerName); stringBuffer.append(" has placed an order of $"); stringBuffer.append(amount); stringBuffer.append(". Press 1 to approve and 2 to reject."); TTSUtils.buildAudio(stringBuffer.toString(), "adminspeech.wav"); } Address toAddress = sipFactory.createAddress(customerPhone); logger.info("preparing to call : "+ toAddress); SipServletRequest sipServletRequest = sipFactory.createRequest(sipApplicationSession, "INVITE", fromAddress, toAddress); URI requestURI = sipFactory.createURI(customerContact); sipServletRequest.setRequestURI(requestURI); //copying the attributes in the sip session since the media listener depends on it Iterator<Entry<String,Object>> attrIterator = attributes.entrySet().iterator(); while (attrIterator.hasNext()) { Map.Entry<java.lang.String, java.lang.Object> entry = (Map.Entry<java.lang.String, java.lang.Object>) attrIterator .next(); sipServletRequest.getSession().setAttribute(entry.getKey(), entry.getValue()); } //Media Server Control Creation MsPeer peer = MsPeerFactory.getPeer("org.mobicents.mscontrol.impl.MsPeerImpl"); MsProvider provider = peer.getProvider(); MsSession session = provider.createSession(); MsConnection connection = session.createNetworkConnection(MediaConnectionListener.PR_JNDI_NAME); MediaConnectionListener listener = new MediaConnectionListener(); listener.setInviteRequest(sipServletRequest); // provider.addConnectionListener(listener); connection.addConnectionListener(listener); sipServletRequest.getSession().setAttribute("connection", connection); connection.modify("$", null); logger.info("waiting to get the SDP from Media Server before sending the INVITE to " + callerAddress + "@" + callerDomain); } catch (Exception e) { logger.error("An unexpected exception occured while creating the request for delivery date", e); } } }