Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 3461bd301989f2c4c91779575bbabe185f9f8d72 0 parents
@hasanein authored
Showing with 1,314 additions and 0 deletions.
  1. +53 −0 pom.xml
  2. BIN  src/.DS_Store
  3. +34 −0 src/.svn/entries
  4. BIN  src/main/.DS_Store
  5. +37 −0 src/main/.svn/entries
  6. BIN  src/main/java/.DS_Store
  7. +31 −0 src/main/java/.svn/entries
  8. BIN  src/main/java/com/.DS_Store
  9. +31 −0 src/main/java/com/.svn/entries
  10. BIN  src/main/java/com/orange/.DS_Store
  11. +31 −0 src/main/java/com/orange/.svn/entries
  12. BIN  src/main/java/com/orange/uklab/.DS_Store
  13. +31 −0 src/main/java/com/orange/uklab/.svn/entries
  14. +62 −0 src/main/java/com/orange/uklab/callmanagement/.svn/entries
  15. +294 −0 src/main/java/com/orange/uklab/callmanagement/.svn/text-base/CallManagerServlet.java.svn-base
  16. +350 −0 src/main/java/com/orange/uklab/callmanagement/CallManagerServlet.java
  17. +28 −0 src/main/resources/.svn/entries
  18. +65 −0 src/main/webapp/.svn/entries
  19. +3 −0  src/main/webapp/.svn/text-base/index.jsp.svn-base
  20. +130 −0 src/main/webapp/WEB-INF/.svn/entries
  21. +6 −0 src/main/webapp/WEB-INF/.svn/text-base/jboss-web.xml.svn-base
  22. +22 −0 src/main/webapp/WEB-INF/.svn/text-base/sip.xml.svn-base
  23. +8 −0 src/main/webapp/WEB-INF/.svn/text-base/web.xml.svn-base
  24. +6 −0 src/main/webapp/WEB-INF/jboss-web.xml
  25. +22 −0 src/main/webapp/WEB-INF/sip.xml
  26. +8 −0 src/main/webapp/WEB-INF/web.xml
  27. +3 −0  src/main/webapp/index.jsp
  28. +31 −0 src/test/.svn/entries
  29. +28 −0 src/test/java/.svn/entries
53 pom.xml
@@ -0,0 +1,53 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.orange.uklab.callmanagement</groupId>
+ <artifactId>CallManagerApp</artifactId>
+ <packaging>war</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>CallManagerApp</name>
+ <url>http://callmanagement.uklab.orange.com</url>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>sip-servlets-spec</artifactId>
+ <version>1.1.10</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>4.2.3</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mobicents.servlet.sip</groupId>
+ <artifactId>sip-servlets-impl</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ <finalName>CallManagerApp</finalName>
+ </build>
+</project>
+
+
+
BIN  src/.DS_Store
Binary file not shown
34 src/.svn/entries
@@ -0,0 +1,34 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+test
+dir
+
+main
+dir
+
BIN  src/main/.DS_Store
Binary file not shown
37 src/main/.svn/entries
@@ -0,0 +1,37 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+java
+dir
+
+resources
+dir
+
+webapp
+dir
+
BIN  src/main/java/.DS_Store
Binary file not shown
31 src/main/java/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/java
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+com
+dir
+
BIN  src/main/java/com/.DS_Store
Binary file not shown
31 src/main/java/com/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/java/com
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+orange
+dir
+
BIN  src/main/java/com/orange/.DS_Store
Binary file not shown
31 src/main/java/com/orange/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/java/com/orange
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+uklab
+dir
+
BIN  src/main/java/com/orange/uklab/.DS_Store
Binary file not shown
31 src/main/java/com/orange/uklab/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/java/com/orange/uklab
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+callmanagement
+dir
+
62 src/main/java/com/orange/uklab/callmanagement/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/java/com/orange/uklab/callmanagement
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+CallManagerServlet.java
+file
+
+
+
+
+2010-06-23T09:36:19.049035Z
+26f7dbfc305653d815764c625a06ce64
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13942
+
294 src/main/java/com/orange/uklab/callmanagement/.svn/text-base/CallManagerServlet.java.svn-base
@@ -0,0 +1,294 @@
+package com.orange.uklab.callmanagement;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import java.util.concurrent.ConcurrentHashMap;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.sip.Address;
+import javax.servlet.sip.B2buaHelper;
+import javax.servlet.sip.SipApplicationSession;
+import javax.servlet.sip.SipErrorEvent;
+import javax.servlet.sip.SipErrorListener;
+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.SipSession.State;
+import javax.servlet.sip.SipURI;
+import javax.servlet.sip.ar.SipRouteModifier;
+import org.apache.log4j.Logger;
+
+public class CallManagerServlet extends SipServlet implements SipErrorListener,
+ Servlet
+{
+ /**
+ * The forking list is implemented temporarily
+ * as a Map, but later on it will be moved to a presistant database storage.
+ */
+ private Map<String, String[]> forkingList;
+ private String preamble = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+
+ public CallManagerServlet()
+ {
+ this.forkingList = null;
+ }
+
+ @Override
+ public void init(ServletConfig servletConfig) throws ServletException
+ {
+ super.init(servletConfig);
+ this.forkingList = new ConcurrentHashMap();
+ this.forkingList.put("sip:968020@192.168.180.131;user=phone", new String[] {"sip:07800850528@192.168.0.38;user=phone"});
+// this.forkingList.put("sip:968020@192.168.0.1", new String[] {"sip:user02@192.168.0.2:4070;user=phone"});
+ }
+
+ @Override
+ protected void doInvite(SipServletRequest req) throws ServletException, IOException
+ {
+ String[] forkingUriList = this.forkingList.get(req.getTo().getURI().toString());
+ System.out.println(preamble + req.getTo().getURI().toString());
+ /*
+ * If the forking list is set for the called number, then process the INVITE
+ * message, otherwise, discard it.
+ */
+ if ((forkingUriList != null) && (forkingUriList.length > 0))
+ {
+ System.out.println(preamble + " processing INVITE message");
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ String sipServletContainerFactoryAttribute = "javax.servlet.sip.SipFactory";
+ SipFactory sipFactory = (SipFactory)getServletContext().getAttribute(sipServletContainerFactoryAttribute);
+ /*
+ *
+ */
+ Map headers = new HashMap();
+ List toHeaderSet = new ArrayList();
+ toHeaderSet.add(forkingUriList[0]);
+ headers.put("To", toHeaderSet);
+ /*
+ * Before forking the INVITE message, we need to inform the calling party
+ * about the progressing processing of the call, that will be achieved via
+ * sending a TRYING response back to the calling party.
+ *
+ * Note: It seems that the TRYING response message is somehow optional, we need
+ * to check the RFC3261 for that.
+ */
+ SipServletResponse tryingResponse = req.createResponse(SipServletResponse.SC_TRYING);
+ tryingResponse.send();
+ /*
+ * Create the forking request, a new SipSession will be created
+ * for this forked request that share the same SipApplicationSession
+ * with the original request. To keep track of the original request, we need
+ * to store the original session inside it.(or store the whole original request object in it.)
+ */
+ SipServletRequest forkedRequest = b2buaHelper.createRequest(req, true, headers);
+ SipURI sipRequestUri = (SipURI)sipFactory.createURI(forkingUriList[0]);
+ forkedRequest.setRequestURI(sipRequestUri);
+ /*
+ * Get the session created for the forked request, and store
+ * the original request session in it as an attribute for later
+ * retrieval.
+ */
+ SipSession forkedSession = forkedRequest.getSession();
+ forkedSession.setAttribute("originalRequest", req);
+ /*
+ * Now we are good to go and send the forked request to where
+ * it should go...
+ */
+ forkedRequest.send();
+ }
+ else
+ {
+ System.out.println(preamble + "There are no forking lists for the called number, INVITE is not forwarded");
+ }
+ }
+
+ /**
+ * This method is called by the doResponse method for the processing of the 2xx
+ * responses.
+ * @param response
+ * @throws ServletException
+ * @throws IOException
+ */
+ @Override
+ protected void doSuccessResponse(SipServletResponse response)
+ throws ServletException, IOException
+ {
+ /**
+ * Check if the method a response for a previous INVITE message,
+ * and quit processing the message otherwise.
+ */
+ if (response.getMethod().indexOf("INVITE") != -1)
+ {
+ /*
+ * Send an ACK back to the called party
+ */
+ SipServletRequest ackForCalled = response.createAck();
+ ackForCalled.send();
+ System.out.println(preamble + "Sending ACK to the called party");
+ /*
+ * Sending a 200OK response back to the caller party
+ */
+ SipServletRequest originalRequest = (SipServletRequest)response.getSession().getAttribute("originalRequest");
+ SipServletResponse okResponseToCaller = originalRequest.createResponse(200);
+ /*
+ * Now we need to copy the content of the message received form the called party
+ * to the calling party, this is the session description content, SDP.
+ */
+ okResponseToCaller.setContentLength(response.getContentLength());
+ if (response.getContent() != null && response.getContentType() != null)
+ {
+ okResponseToCaller.setContent(response.getContent(), response.getContentType());
+ }
+ // Now we shall send the 200 OK message to the calling party
+ System.out.println(preamble + "Sending a 200 OK resoponse to the calling party");
+ okResponseToCaller.send();
+ }
+ /*
+ * Check if the response is related to a previous BYE request, and simply
+ * invalidate the requester session, assuming that the other end of the session is already
+ * invalidated when the other pary sent a BYE request. This will also invlove the invalidation
+ * of the whole application session as well.
+ */
+ if (response.getMethod().indexOf("BYE") != -1)
+ {
+ /*
+ * Get the session corresponds to the BYE response and
+ * invalidate it.
+ */
+ SipSession byeResponseSession = response.getSession(false);
+ if ((byeResponseSession != null) && (byeResponseSession.isValid()))
+ {
+ byeResponseSession.invalidate();
+ }
+ /*
+ * Get the whole application session and invalidate
+ * it as well.
+ */
+ SipApplicationSession appSession = response.getApplicationSession(false);
+ if ((appSession != null) && (appSession.isValid()))
+ {
+ appSession.invalidate();
+ }
+ }
+ }
+
+ /**
+ * This method will be called by the doResponse method for the processing
+ * of the 1xx response messages
+ * @param resp
+ * @throws javax.servlet.ServletException
+ * @throws java.io.IOException
+ */
+ @Override
+ protected void doProvisionalResponse(SipServletResponse resp)
+ throws javax.servlet.ServletException, java.io.IOException
+ {
+ System.out.println(preamble + "Received a ringing response for status code of " + resp.getStatus());
+ /**
+ * Here we need to retrieve the original request that we have already stored inside the forked invite
+ * message, and this will help us construct a ringing response back to the caller.
+ */
+ SipServletRequest originalRequest = (SipServletRequest)resp.getSession().getAttribute("originalRequest");
+ SipServletResponse ringingResponse = originalRequest.createResponse(SipServletResponse.SC_RINGING);
+ ringingResponse.send();
+ System.out.println(preamble + "The ringing response has been sent.");
+ }
+
+ public void noAckReceived(SipErrorEvent ee) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void noPrackReceived(SipErrorEvent ee) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /**
+ * When handling BYE requests, we need to confirm the request with a 200 OK
+ * response back to the requesting party (whether being calling or called party, which
+ * depends on who hangs up first during an actibe call session.
+ * On the other hand, we have to generate another request for the other leg of the
+ * call and send a BYE request to it, the responses that the client generates for this
+ * BYE requet need to be handled by the doSuccessResponse accordingly by invalidating the
+ * session that is requested to be terminated.
+ */
+ protected void doBye(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ /*
+ * Sending a 200 OK back to the requesting party
+ */
+ SipServletResponse byeResponseToRequestor = req.createResponse(SipServletResponse.SC_OK);
+ byeResponseToRequestor.send();
+ /*
+ * Now we need to retrieve the SipSession associated with rhe received request, and then
+ * we need to get any linked session with that session and use it to construct a BYE request to
+ * that end of the call. The original request session need to be invalidated.
+ */
+ SipSession byeRequestorSession = req.getSession();
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ SipSession theOtherPartySession = b2buaHelper.getLinkedSession(byeRequestorSession);
+ SipServletRequest byeRequestToTheOtherEnd = theOtherPartySession.createRequest("BYE");
+ byeRequestToTheOtherEnd.send();
+ /*
+ * The BYE requestor session is to be invalidated here, as an 200 OK response has been already
+ * sent. The other end session will be invalidated upon the reception of the 200 OK from the
+ * other end of the call.
+ */
+ if ((byeRequestorSession != null) && (byeRequestorSession.isValid()))
+ {
+ byeRequestorSession.invalidate();
+ }
+ }
+
+ /**
+ * The handling of the Cancel requests is a bit tricky, here is the story:
+ * We are assuming here that the Cancel request is always generated by the
+ * calling party to cancel the INVITE request it has sent before the called
+ * party picks up (sends a 200 OK response. From the B2B side, we need to
+ * cancel the request that we have forked to the called party.
+ * Thus, to do that we need to get the session associated with the Cancel
+ * request, then using the B2bHelper we can get the session linked and associated
+ * with that session under one SipApplicationSession and then we need to retrieve the
+ * original request we have stored in the forked session. Having that done, we
+ * need to get the forked request (which is the request that we need to cancel) that
+ * is generated basing on the parameters of the orginal request (except for modifying
+ * the To field) and then create a cancel request basing on it. and afterwards we need to
+ * send the cancel request to the other end of the call.
+ * @param req
+ * @throws javax.servlet.ServletException
+ * @throws java.io.IOException
+ */
+ protected void doCancel(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ SipSession session = req.getSession();
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ SipSession theOtherSession = b2buaHelper.getLinkedSession(session);
+ SipServletRequest originalRequest = (SipServletRequest)theOtherSession.getAttribute("originalRequest");
+ SipServletRequest cancelRequest = b2buaHelper.getLinkedSipServletRequest(originalRequest).createCancel();
+ cancelRequest.send();
+ }
+
+ protected void doRegister(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ System.out.println(preamble + "Processing registration request from " + req.getFrom().toString());
+ SipServletResponse registrationResponse = req.createResponse(SipServletResponse.SC_OK);
+ Address address = req.getAddressHeader("Contact");
+ registrationResponse.setAddressHeader("Contact", address);
+ registrationResponse.send();
+ }
+}
350 src/main/java/com/orange/uklab/callmanagement/CallManagerServlet.java
@@ -0,0 +1,350 @@
+package com.orange.uklab.callmanagement;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.sip.Address;
+import javax.servlet.sip.B2buaHelper;
+import javax.servlet.sip.SipApplicationSession;
+import javax.servlet.sip.SipErrorEvent;
+import javax.servlet.sip.SipErrorListener;
+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 java.util.Iterator;
+import javax.servlet.sip.SipSession.State;
+import javax.servlet.sip.SipURI;
+import javax.servlet.sip.ar.SipRouteModifier;
+import org.mobicents.servlet.sip.core.session.MobicentsSipApplicationSession;
+import org.mobicents.servlet.sip.message.*;
+import org.mobicents.servlet.sip.startup.*;
+
+public class CallManagerServlet extends SipServlet implements SipErrorListener,
+ Servlet
+{
+ /**
+ * The forking list is implemented temporarily
+ * as a Map, but later on it will be moved to a presistant database storage.
+ */
+ private Map<String, String[]> forkingList;
+ private String preamble = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+
+ public CallManagerServlet()
+ {
+ this.forkingList = null;
+ }
+
+ @Override
+ public void init(ServletConfig servletConfig) throws ServletException
+ {
+ super.init(servletConfig);
+ this.forkingList = new ConcurrentHashMap();
+// this.forkingList.put("sip:968020@192.168.180.131;user=phone", new String[] {"sip:07800850528@192.168.0.38;user=phone", "sip:07746663954@192.168.0.38;user=phone", "sip:02088495849@192.168.0.38;user=phone"});
+// this.forkingList.put("sip:968020@192.168.180.131;user=phone", new String[] {"sip:07800850528@192.168.0.38;user=phone", "sip:07746663954@192.168.0.38;user=phone"});
+ this.forkingList.put("sip:968020@192.168.180.131;user=phone", new String[] {"sip:07800850528@192.168.0.38;user=phone"});
+// this.forkingList.put("sip:968020@192.168.0.1", new String[] {"sip:user02@192.168.0.2:4070;user=phone"});
+ }
+
+ /*
+ * The doInvite method will try to ring whatever number of forkedToNumbers it gets for the given called number, then
+ * the system should cancel the requests sent to the other devices whenever any one of the devices ring.
+ */
+ @Override
+ protected void doInvite(SipServletRequest req) throws ServletException, IOException
+ {
+ /*
+ * Mark the original call session so as not to be considered when
+ * cancelling the not picked up parties.
+ */
+ req.getSession().setAttribute("cancelCandidate", false);
+ String[] forkingUriList = this.forkingList.get(req.getTo().getURI().toString());
+ System.out.println(preamble + req.getTo().getURI().toString());
+ /*
+ * If the forking list is set for the called number, then process the INVITE
+ * message, otherwise, discard it.
+ */
+ if ((forkingUriList != null) && (forkingUriList.length > 0))
+ {
+ System.out.println(preamble + " processing INVITE message");
+ System.out.println(preamble + "There are " + forkingUriList.length + " devices for the call to be forked to for the called nummber of " + req.getTo().toString());
+
+ /*
+ * Before forking the INVITE message, we need to inform the calling party
+ * about the progressing processing of the call, that will be achieved via
+ * sending a TRYING response back to the calling party. we have put this
+ * excerpt of code here as we want to send the trying message only once
+ * to the calling party.
+ *
+ * Note: It seems that the TRYING response message is somehow optional, we need
+ * to check the RFC3261 for that.
+ */
+ SipServletResponse tryingResponse = req.createResponse(SipServletResponse.SC_TRYING);
+ tryingResponse.send();
+
+ for (String forkingToNumber : forkingUriList)
+ {
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ String sipServletContainerFactoryAttribute = "javax.servlet.sip.SipFactory";
+ SipFactory sipFactory = (SipFactory)getServletContext().getAttribute(sipServletContainerFactoryAttribute);
+ /*
+ *
+ */
+ Map headers = new HashMap();
+ List toHeaderSet = new ArrayList();
+ toHeaderSet.add(forkingToNumber);
+ headers.put("To", toHeaderSet);
+ /*
+ * Create the forking request, a new SipSession will be created
+ * for this forked request that share the same SipApplicationSession
+ * with the original request. To keep track of the original request, we need
+ * to store the original session inside it.(or store the whole original request object in it.)
+ */
+ SipServletRequest forkedRequest = b2buaHelper.createRequest(req, true, headers);
+ SipURI sipRequestUri = (SipURI)sipFactory.createURI(forkingToNumber);
+ forkedRequest.setRequestURI(sipRequestUri);
+ /*
+ * Get the session created for the forked request, and store
+ * the original request session in it as an attribute for later
+ * retrieval.
+ */
+ SipSession forkedSession = forkedRequest.getSession();
+ forkedSession.setAttribute("originalRequest", req);
+ /*
+ * We need to mark the forked session and define it as
+ * being a cancel candidate in case the call has not
+ * been picked up by the party associated with the session.
+ * If the associated party picked up the call then the session
+ * will be designated as not being a cancel candidate.
+ */
+ forkedSession.setAttribute("cancelCandidate", true);
+ /*
+ * Now we are good to go and send the forked request to where
+ * it should go...
+ */
+ System.out.println("Forking INVITE for " + forkingToNumber);
+ forkedRequest.send();
+ }
+ }
+ else
+ {
+ System.out.println(preamble + "There are no forking lists for the called number, INVITE is not forwarded");
+ }
+ }
+
+ /**
+ * This method is called by the doResponse method for the processing of the 2xx
+ * responses.
+ * In this version, and upon the reception of the 200 Ok response of an INVITE message
+ * we need to look for the other forked calls and send a cancel request to them to
+ * stop them from ringing...
+ * @param response
+ * @throws ServletException
+ * @throws IOException
+ */
+ @Override
+ protected void doSuccessResponse(SipServletResponse response)
+ throws ServletException, IOException
+ {
+ /**
+ * Check if the method a response for a previous INVITE message,
+ * and quit processing the message otherwise.
+ */
+ if (response.getMethod().indexOf("INVITE") != -1)
+ {
+ /*
+ * Send an ACK back to the called party
+ */
+ SipServletRequest ackForCalled = response.createAck();
+ ackForCalled.send();
+ System.out.println(preamble + "Sending ACK to the called party");
+ /*
+ * Sending a 200OK response back to the caller party
+ */
+ SipServletRequest originalRequest = (SipServletRequest)response.getSession().getAttribute("originalRequest");
+ SipServletResponse okResponseToCaller = originalRequest.createResponse(200);
+ /*
+ * Now we need to copy the content of the message received form the called party
+ * to the calling party, this is the session description content, SDP.
+ */
+ okResponseToCaller.setContentLength(response.getContentLength());
+ if (response.getContent() != null && response.getContentType() != null)
+ {
+ okResponseToCaller.setContent(response.getContent(), response.getContentType());
+ }
+ // Now we shall send the 200 OK message to the calling party
+ System.out.println(preamble + "Sending a 200 OK resoponse to the calling party");
+ okResponseToCaller.send();
+ /*
+ * Mark the session that picked up the call, so that it will not
+ * be considered for session cancellation.
+ */
+ response.getSession().setAttribute("cancelCandidate", false);
+ /*
+ * To help in retrieving the forked sessions only that haven't picked
+ * up the call and then send a cancel request to them, we should execlude the
+ * original caller session and the session of the party that picked up the call from
+ * sending a CANCEL request to them.
+ */
+ cancelUnpickedUpParties(originalRequest);
+ }
+ /*
+ * Check if the response is related to a previous BYE request, and simply
+ * invalidate the requester session, assuming that the other end of the session is already
+ * invalidated when the other pary sent a BYE request. This will also invlove the invalidation
+ * of the whole application session as well.
+ */
+ if (response.getMethod().indexOf("BYE") != -1)
+ {
+ /*
+ * Get the session corresponds to the BYE response and
+ * invalidate it.
+ */
+ SipSession byeResponseSession = response.getSession(false);
+ if ((byeResponseSession != null) && (byeResponseSession.isValid()))
+ {
+ byeResponseSession.invalidate();
+ }
+ /*
+ * Get the whole application session and invalidate
+ * it as well.
+ */
+ SipApplicationSession appSession = response.getApplicationSession(false);
+ if ((appSession != null) && (appSession.isValid()))
+ {
+ appSession.invalidate();
+ }
+ }
+ }
+
+ /**
+ * This method will be called by the doResponse method for the processing
+ * of the 1xx response messages
+ * @param resp
+ * @throws javax.servlet.ServletException
+ * @throws java.io.IOException
+ */
+ @Override
+ protected void doProvisionalResponse(SipServletResponse resp)
+ throws javax.servlet.ServletException, java.io.IOException
+ {
+ System.out.println(preamble + "Received a ringing response for status code of " + resp.getStatus());
+ /**
+ * Here we need to retrieve the original request that we have already stored inside the forked invite
+ * message, and this will help us construct a ringing response back to the caller.
+ */
+ SipServletRequest originalRequest = (SipServletRequest)resp.getSession().getAttribute("originalRequest");
+ SipServletResponse ringingResponse = originalRequest.createResponse(SipServletResponse.SC_RINGING);
+ ringingResponse.send();
+ System.out.println(preamble + "The ringing response has been sent.");
+ }
+
+ public void noAckReceived(SipErrorEvent ee) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void noPrackReceived(SipErrorEvent ee) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /**
+ * When handling BYE requests, we need to confirm the request with a 200 OK
+ * response back to the requesting party (whether being calling or called party, which
+ * depends on who hangs up first during an active call session.
+ * On the other hand, we have to generate another request for the other leg of the
+ * call and send a BYE request to it, the responses that the client generates for this
+ * BYE requet need to be handled by the doSuccessResponse accordingly by invalidating the
+ * session that is requested to be terminated.
+ */
+ protected void doBye(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ /*
+ * Sending a 200 OK back to the requesting party
+ */
+ SipServletResponse byeResponseToRequestor = req.createResponse(SipServletResponse.SC_OK);
+ byeResponseToRequestor.send();
+ /*
+ * Now we need to retrieve the SipSession associated with rhe received request, and then
+ * we need to get any linked session with that session and use it to construct a BYE request to
+ * that end of the call. The original request session need to be invalidated.
+ */
+ SipSession byeRequestorSession = req.getSession();
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ SipSession theOtherPartySession = b2buaHelper.getLinkedSession(byeRequestorSession);
+ SipServletRequest byeRequestToTheOtherEnd = theOtherPartySession.createRequest("BYE");
+ byeRequestToTheOtherEnd.send();
+ /*
+ * The BYE requestor session is to be invalidated here, as an 200 OK response has been already
+ * sent. The other end session will be invalidated upon the reception of the 200 OK from the
+ * other end of the call.
+ */
+ if ((byeRequestorSession != null) && (byeRequestorSession.isValid()))
+ {
+ byeRequestorSession.invalidate();
+ }
+ }
+
+ /**
+ * The handling of the Cancel requests is a bit tricky, here is the story:
+ * We are assuming here that the Cancel request is always generated by the
+ * calling party to cancel the INVITE request it has sent before the called
+ * party picks up (sends a 200 OK response. From the B2B side, we need to
+ * cancel the request that we have forked to the called party.
+ * Thus, to do that we need to get the session associated with the Cancel
+ * request, then using the B2bHelper we can get the session linked and associated
+ * with that session under one SipApplicationSession and then we need to retrieve the
+ * original request we have stored in the forked session. Having that done, we
+ * need to get the forked request (which is the request that we need to cancel) that
+ * is generated basing on the parameters of the orginal request (except for modifying
+ * the To field) and then create a cancel request basing on it. and afterwards we need to
+ * send the cancel request to the other end of the call.
+ * @param req
+ * @throws javax.servlet.ServletException
+ * @throws java.io.IOException
+ */
+ protected void doCancel(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ SipSession session = req.getSession();
+ B2buaHelper b2buaHelper = req.getB2buaHelper();
+ SipSession theOtherSession = b2buaHelper.getLinkedSession(session);
+ SipServletRequest originalRequest = (SipServletRequest)theOtherSession.getAttribute("originalRequest");
+ SipServletRequest cancelRequest = b2buaHelper.getLinkedSipServletRequest(originalRequest).createCancel();
+ cancelRequest.send();
+ }
+
+ protected void doRegister(SipServletRequest req)
+ throws javax.servlet.ServletException,java.io.IOException
+ {
+ System.out.println(preamble + "Processing registration request from " + req.getFrom().toString());
+ SipServletResponse registrationResponse = req.createResponse(SipServletResponse.SC_OK);
+ Address address = req.getAddressHeader("Contact");
+ registrationResponse.setAddressHeader("Contact", address);
+ registrationResponse.send();
+ }
+
+ private void cancelUnpickedUpParties(SipServletRequest originalRequest)
+ {
+ /*
+ * Get the SipApplicationSession that this request is part of
+ */
+ System.out.println(preamble + "CANCEL UNPICKED UP STARTED1");
+ MobicentsSipApplicationSession sipApplicationSession = (MobicentsSipApplicationSession)originalRequest.getApplicationSession();
+ SipContext sipContext = sipApplicationSession.getSipContext();
+ int activeSessions = sipContext.getSipManager().getActiveSipApplicationSessions();
+ System.out.println(preamble + "ActiveSessions: " + activeSessions);
+ }
+}
28 src/main/resources/.svn/entries
@@ -0,0 +1,28 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/resources
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
65 src/main/webapp/.svn/entries
@@ -0,0 +1,65 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/webapp
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+index.jsp
+file
+
+
+
+
+2010-06-23T09:36:19.501540Z
+cac16546e7b8aa91903c96b79ae6d4cf
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+40
+
+WEB-INF
+dir
+
3  src/main/webapp/.svn/text-base/index.jsp.svn-base
@@ -0,0 +1,3 @@
+<%
+ out.println("CallManagerApp");
+%>
130 src/main/webapp/WEB-INF/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/main/webapp/WEB-INF
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+jboss-web.xml
+file
+
+
+
+
+2010-06-23T09:36:19.407918Z
+25cd735a7b1742a19350dd5c30b157eb
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+281
+
+sip.xml
+file
+
+
+
+
+2010-06-23T09:36:19.423522Z
+3312d03a2b485f089ccdd802e4e4e3bb
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+763
+
+web.xml
+file
+
+
+
+
+2010-06-23T09:36:19.439125Z
+6e73dc60686dfdcd62b0489449edfc07
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+476
+
6 src/main/webapp/WEB-INF/.svn/text-base/jboss-web.xml.svn-base
@@ -0,0 +1,6 @@
+<jboss-web>
+ <!-- Uncomment the security-domain to enable security. You will
+ need to edit the htmladaptor login configuration to setup the
+ login modules used to authentication users. -->
+ <security-domain>java:/jaas/call-management</security-domain>
+</jboss-web>
22 src/main/webapp/WEB-INF/.svn/text-base/sip.xml.svn-base
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<sip-app>
+ <app-name>com.orange.uklab.callmanagement.CallManagerServlet</app-name>
+ <display-name>Call Manager Servlet</display-name>
+ <description>Call Manager Servlet</description>
+ <servlet>
+ <servlet-name>CallManagerServlet</servlet-name>
+ <display-name>CallManagerServlet</display-name>
+ <description>Call Manager Servlet</description>
+ <servlet-class>
+ com.orange.uklab.callmanagement.CallManagerServlet
+ </servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <listener>
+ <listener-class>
+ com.orange.uklab.callmanagement.CallManagerServlet
+ </listener-class>
+ </listener>
+</sip-app>
8 src/main/webapp/WEB-INF/.svn/text-base/web.xml.svn-base
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+ <description>Call Management Application</description>
+ <display-name>Call Manager</display-name>
+ <welcome-file-list>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+</web-app>
6 src/main/webapp/WEB-INF/jboss-web.xml
@@ -0,0 +1,6 @@
+<jboss-web>
+ <!-- Uncomment the security-domain to enable security. You will
+ need to edit the htmladaptor login configuration to setup the
+ login modules used to authentication users. -->
+ <security-domain>java:/jaas/call-management</security-domain>
+</jboss-web>
22 src/main/webapp/WEB-INF/sip.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<sip-app>
+ <app-name>com.orange.uklab.callmanagement.CallManagerServlet</app-name>
+ <display-name>Call Manager Servlet</display-name>
+ <description>Call Manager Servlet</description>
+ <servlet>
+ <servlet-name>CallManagerServlet</servlet-name>
+ <display-name>CallManagerServlet</display-name>
+ <description>Call Manager Servlet</description>
+ <servlet-class>
+ com.orange.uklab.callmanagement.CallManagerServlet
+ </servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <listener>
+ <listener-class>
+ com.orange.uklab.callmanagement.CallManagerServlet
+ </listener-class>
+ </listener>
+</sip-app>
8 src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+ <description>Call Management Application</description>
+ <display-name>Call Manager</display-name>
+ <welcome-file-list>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+</web-app>
3  src/main/webapp/index.jsp
@@ -0,0 +1,3 @@
+<%
+ out.println("CallManagerApp");
+%>
31 src/test/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/test
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
+java
+dir
+
28 src/test/java/.svn/entries
@@ -0,0 +1,28 @@
+10
+
+dir
+9812
+svn://mks-server/personal/hasanein/CallForkingApp/src/test/java
+svn://mks-server
+
+
+
+2010-06-23T09:36:33.986848Z
+9812
+hasanein
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8ce4efad-494c-ff44-bab8-f8ffbb5ec2ff
+
Please sign in to comment.
Something went wrong with that request. Please try again.