Part of my current project to implement a fully JEE IP Telephony stack is to obviously take the time to brainstorm designs and to come up with proof of concepts. I am currently did a bit of coding writing an abstracted media facade layer to wrap libraries like JSR390 for instance. I spend time to implement the following JMock Expectation for SIP interaction.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.sip.Address; import javax.servlet.sip.ServletParseException; 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 org.jmock.Expectations; import org.jmock.api.Invocation; import org.jmock.integration.junit3.MockObjectTestCase; import org.jmock.lib.action.CustomAction; public class SipExpectations extends Expectations { private SipServletRequest sipRequest; private SipSession sipSession; private ServletConfig servletConfig; private ServletContext servletContext; private SipFactory sipFactory; private SipApplicationSession sipApplicationSession; private SipServletResponse sipResponse; private Address sipAddress; private String sipMethod; private String contentValue; private String contentType; private Map sessionValues = new HashMap(); private Map requestValues = new HashMap(); public SipExpectations(MockObjectTestCase mockTest) throws IOException, ServletParseException { sipRequest = mockTest.mock(SipServletRequest.class); sipSession = mockTest.mock(SipSession.class); servletConfig = mockTest.mock(ServletConfig.class); servletContext = mockTest.mock(ServletContext.class); sipFactory = mockTest.mock(SipFactory.class); sipApplicationSession = mockTest.mock(SipApplicationSession.class); sipResponse = mockTest.mock(SipServletResponse.class); sipAddress = mockTest.mock(Address.class); allowing(sipSession).createRequest(with(any(String.class))); will(returnValue(sipRequest)); allowing(servletConfig).getServletContext(); will(returnValue(servletContext)); allowing(servletContext).getAttribute(SipServlet.SIP_FACTORY); will(returnValue(sipFactory)); allowing(sipFactory).createApplicationSession(); will(returnValue(sipApplicationSession)); allowing(sipFactory).createRequest(with(any(SipApplicationSession.class)), with(any(String.class)), with(any(String.class)), with(any(String.class))); will(returnValue(sipRequest)); allowing(sipSession).setAttribute(with(any(String.class)), with(any(Object.class))); will(new CustomAction("session.setAttribute") { @Override public Object invoke(Invocation invocation) throws Throwable { sessionValues.put(invocation.getParameter(0).toString(), invocation.getParameter(1)); return null; } }); allowing(sipSession).getAttribute(with(any(String.class))); will(new CustomAction("session.getAttribute") { @Override public Object invoke(Invocation invocation) throws Throwable { return sessionValues.get(invocation.getParameter(0)); } }); allowing(sipRequest).setAttribute(with(any(String.class)), with(any(Object.class))); will(new CustomAction("request.setAttribute") { @Override public Object invoke(Invocation invocation) throws Throwable { requestValues.put(invocation.getParameter(0).toString(), invocation.getParameter(1)); return null; } }); allowing(sipRequest).getAttribute(with(any(String.class))); will(new CustomAction("request.getAttribute") { @Override public Object invoke(Invocation invocation) throws Throwable { return requestValues.get(invocation.getParameter(0)); } }); allowing(sipRequest).createResponse(with(any(Integer.class))); will(returnValue(sipResponse)); allowing(sipRequest).setContent(with(any(Object.class)), with(any(String.class))); allowing(sipRequest).send(); will(new CustomAction("sipRequest.send") { @Override public Object invoke(Invocation invocation) throws Throwable { System.out.println("\nSip Request Send\nContent Type: " + contentType + "\nContent Value: " + contentValue+"\n"); return null; } }); allowing(sipRequest).getSession(); will(returnValue(sipSession)); allowing(sipResponse).getMethod(); will(new CustomAction("sipResponse.getMethod") { @Override public Object invoke(Invocation invocation) throws Throwable { return getSipMethod(); } }); allowing(sipResponse).getContent(); will(new CustomAction("sipResponse.getContent") { @Override public Object invoke(Invocation invocation) throws Throwable { return getContentValue(); } }); allowing(sipResponse).getContentType(); will(new CustomAction("sipResponse.getContentType") { @Override public Object invoke(Invocation invocation) throws Throwable { return getContentType(); } }); allowing(sipResponse).getStatus(); will(returnValue(SipServletResponse.SC_OK)); allowing(sipResponse).getSession(); will(returnValue(sipSession)); allowing(sipResponse).createAck(); will(returnValue(sipRequest)); allowing(sipResponse).getTo(); will(returnValue(sipAddress)); allowing(sipResponse).send(); allowing(sipAddress).getParameter("tag"); will(returnValue(UUID.randomUUID().toString())); } public SipSession getSipSession() { return sipSession; } public ServletConfig getServletConfig() { return servletConfig; } public ServletContext getServletContext() { return servletContext; } public SipFactory getSipFactory() { return sipFactory; } public SipServletRequest getSipRequest() { return sipRequest; } public SipApplicationSession getSipApplicationSession() { return sipApplicationSession; } public SipServletResponse getSipResponse() { return sipResponse; } public Map getSessionValues() { return sessionValues; } public Map getRequestValues() { return requestValues; } public String getContentValue() { return contentValue; } public void setContentValue(String contentValue) { this.contentValue = contentValue; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public String getSipMethod() { return sipMethod; } public void setSipMethod(String sipMethod) { this.sipMethod = sipMethod; } } |
Not complete though it is good enough to simple functional test relying on SIP communication to another server. For example:
public class MockTest extends MockObjectTestCase { public void testMockInvoke() { try { SipExpectations sipExp = new SipExpectations(this); checking(sipExp); SipServletRequest request = sipExp.getSipSession().createRequest("INFO"); request.setContent("Hallo", "sip/text"); request.send(); sipExp.setContentType("sip/text"); sipExp.setContentValue("Bye"); sipExp.setSipMethod("INFO"); YourSipServletImplementationInstance.doResponse(sipExp.getSipResponse()); } catch (Exception e) { e.printStackTrace(); } } }
