/* * Conditions Of Use * * This software was developed by employees of the National Institute of * Standards and Technology (NIST), an agency of the Federal Government. * Pursuant to title 15 Untied States Code Section 105, works of NIST * employees are not subject to copyright protection in the United States * and are considered to be in the public domain. As a result, a formal * license is not needed to use the software. * * This software is provided by NIST as a service and is expressly * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT * AND DATA ACCURACY. NIST does not warrant or make any representations * regarding the use of the software or the results thereof, including but * not limited to the correctness, accuracy, reliability or usefulness of * the software. * * Permission to use this software is contingent upon your acceptance * of the terms of this agreement * * . * */ /******************************************************************************* * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * *******************************************************************************/ package gov.nist.javax.sip.message; import java.text.ParseException; import javax.sip.header.*; import java.util.LinkedList; import java.util.List; import gov.nist.javax.sip.header.*; import javax.sip.message.*; import javax.sip.address.*; import gov.nist.javax.sip.parser.*; /** * Message Factory implementation * * @version 1.2 $Revision: 1.24 $ $Date: 2010-05-06 14:08:03 $ * @since 1.1 * * @author M. Ranganathan <br/> * @author Olivier Deruelle <br/> * */ @SuppressWarnings("unchecked") public class MessageFactoryImpl implements MessageFactory, MessageFactoryExt { private boolean testing = false; private boolean strict = true; private static String defaultContentEncodingCharset = "UTF-8"; /* * The UserAgent header to include for all requests created from this message factory. */ private static UserAgentHeader userAgent; /* * The Server header to include */ private static ServerHeader server; public void setStrict(boolean strict) { this.strict = strict; } /** * This is for testing -- allows you to generate invalid requests */ public void setTest(boolean flag) { this.testing = flag; } /** * Creates a new instance of MessageFactoryImpl */ public MessageFactoryImpl() { } /** * Creates a new Request message of type specified by the method paramater, * containing the URI of the Request, the mandatory headers of the message * with a body in the form of a Java object and the body content type. * * @param requestURI - * the new URI object of the requestURI value of this Message. * @param method - * the new string of the method value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @param content - * the new Object of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the method or the body. */ public Request createRequest(javax.sip.address.URI requestURI, String method, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, ContentTypeHeader contentType, Object content) throws ParseException { if (requestURI == null || method == null || callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException("Null parameters"); SIPRequest sipRequest = new SIPRequest(); sipRequest.setRequestURI(requestURI); sipRequest.setMethod(method); sipRequest.setCallId(callId); sipRequest.setCSeq(cSeq); sipRequest.setFrom(from); sipRequest.setTo(to); sipRequest.setVia(via); sipRequest.setMaxForwards(maxForwards); sipRequest.setContent(content, contentType); if ( userAgent != null ) { sipRequest.setHeader(userAgent); } return sipRequest; } /** * Creates a new Request message of type specified by the method paramater, * containing the URI of the Request, the mandatory headers of the message * with a body in the form of a byte array and body content type. * * @param requestURI - * the new URI object of the requestURI value of this Message. * @param method - * the new string of the method value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @param content - * the new byte array of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the method or the body. */ public Request createRequest(URI requestURI, String method, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, byte[] content, ContentTypeHeader contentType) throws ParseException { if (requestURI == null || method == null || callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new ParseException( "JAIN-SIP Exception, some parameters are missing" + ", unable to create the request", 0); SIPRequest sipRequest = new SIPRequest(); sipRequest.setRequestURI(requestURI); sipRequest.setMethod(method); sipRequest.setCallId(callId); sipRequest.setCSeq(cSeq); sipRequest.setFrom(from); sipRequest.setTo(to); sipRequest.setVia(via); sipRequest.setMaxForwards(maxForwards); sipRequest.setHeader((ContentType) contentType); sipRequest.setMessageContent(content); if ( userAgent != null ) { sipRequest.setHeader(userAgent); } return sipRequest; } /** * Creates a new Request message of type specified by the method paramater, * containing the URI of the Request, the mandatory headers of the message. * This new Request does not contain a body. * * @param requestURI - * the new URI object of the requestURI value of this Message. * @param method - * the new string of the method value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the method. */ public Request createRequest(URI requestURI, String method, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards) throws ParseException { if (requestURI == null || method == null || callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null) throw new ParseException( "JAIN-SIP Exception, some parameters are missing" + ", unable to create the request", 0); SIPRequest sipRequest = new SIPRequest(); sipRequest.setRequestURI(requestURI); sipRequest.setMethod(method); sipRequest.setCallId(callId); sipRequest.setCSeq(cSeq); sipRequest.setFrom(from); sipRequest.setTo(to); sipRequest.setVia(via); sipRequest.setMaxForwards(maxForwards); if (userAgent != null) { sipRequest.setHeader(userAgent); } return sipRequest; } // Standard Response Creation methods /** * Creates a new Response message of type specified by the statusCode * paramater, containing the mandatory headers of the message with a body in * the form of a Java object and the body content type. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @param content - * the new Object of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, Object content, ContentTypeHeader contentType) throws ParseException { if (callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException(" unable to create the response"); SIPResponse sipResponse = new SIPResponse(); StatusLine statusLine = new StatusLine(); statusLine.setStatusCode(statusCode); String reasonPhrase = SIPResponse.getReasonPhrase(statusCode); //if (reasonPhrase == null) // throw new ParseException(statusCode + " Unkown ", 0); statusLine.setReasonPhrase(reasonPhrase); sipResponse.setStatusLine(statusLine); sipResponse.setCallId(callId); sipResponse.setCSeq(cSeq); sipResponse.setFrom(from); sipResponse.setTo(to); sipResponse.setVia(via); sipResponse.setMaxForwards(maxForwards); sipResponse.setContent(content, contentType); if (userAgent != null) { sipResponse.setHeader(userAgent); } return sipResponse; } /** * Creates a new Response message of type specified by the statusCode * paramater, containing the mandatory headers of the message with a body in * the form of a byte array and the body content type. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @param content - * the new byte array of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, byte[] content, ContentTypeHeader contentType) throws ParseException { if (callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException("Null params "); SIPResponse sipResponse = new SIPResponse(); sipResponse.setStatusCode(statusCode); sipResponse.setCallId(callId); sipResponse.setCSeq(cSeq); sipResponse.setFrom(from); sipResponse.setTo(to); sipResponse.setVia(via); sipResponse.setMaxForwards(maxForwards); sipResponse.setHeader((ContentType) contentType); sipResponse.setMessageContent(content); if (userAgent != null) { sipResponse.setHeader(userAgent); } return sipResponse; } /** * Creates a new Response message of type specified by the statusCode * paramater, containing the mandatory headers of the message. This new * Response does not contain a body. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode. */ public Response createResponse(int statusCode, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards) throws ParseException { if (callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null) throw new ParseException( "JAIN-SIP Exception, some parameters are missing" + ", unable to create the response", 0); SIPResponse sipResponse = new SIPResponse(); sipResponse.setStatusCode(statusCode); sipResponse.setCallId(callId); sipResponse.setCSeq(cSeq); sipResponse.setFrom(from); sipResponse.setTo(to); sipResponse.setVia(via); sipResponse.setMaxForwards(maxForwards); if (userAgent != null) { sipResponse.setHeader(userAgent); } return sipResponse; } // Response Creation methods based on a Request /** * Creates a new Response message of type specified by the statusCode * paramater, based on a specific Request with a new body in the form of a * Java object and the body content type. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param request - * the received Reqest object upon which to base the Response. * @param content - * the new Object of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, Request request, ContentTypeHeader contentType, Object content) throws ParseException { if (request == null || content == null || contentType == null) throw new NullPointerException("null parameters"); SIPRequest sipRequest = (SIPRequest) request; SIPResponse sipResponse = sipRequest.createResponse(statusCode); sipResponse.setContent(content, contentType); if (server != null) { sipResponse.setHeader(server); } return sipResponse; } /** * Creates a new Response message of type specified by the statusCode * paramater, based on a specific Request with a new body in the form of a * byte array and the body content type. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param request - * the received Reqest object upon which to base the Response. * @param content - * the new byte array of the body content value of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, Request request, ContentTypeHeader contentType, byte[] content) throws ParseException { if (request == null || content == null || contentType == null) throw new NullPointerException("null Parameters"); SIPRequest sipRequest = (SIPRequest) request; SIPResponse sipResponse = sipRequest.createResponse(statusCode); sipResponse.setHeader((ContentType) contentType); sipResponse.setMessageContent(content); if (server != null) { sipResponse.setHeader(server); } return sipResponse; } /** * Creates a new Response message of type specified by the statusCode * paramater, based on a specific Request message. This new Response does * not contain a body. * * @param statusCode - * the new integer of the statusCode value of this Message. * @param request - * the received Reqest object upon which to base the Response. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode. */ public Response createResponse(int statusCode, Request request) throws ParseException { if (request == null) throw new NullPointerException("null parameters"); // if (LogWriter.needsLogging) // LogWriter.logMessage("createResponse " + request); SIPRequest sipRequest = (SIPRequest) request; SIPResponse sipResponse = sipRequest.createResponse(statusCode); // Remove the content from the message (Bug report from // Antonis Karydas. sipResponse.removeContent(); sipResponse.removeHeader(ContentTypeHeader.NAME); if (server != null) { sipResponse.setHeader(server); } return sipResponse; } /** * Creates a new Request message of type specified by the method paramater, * containing the URI of the Request, the mandatory headers of the message * with a body in the form of a byte array and body content type. * * @param requestURI - * the new URI object of the requestURI value of this Message. * @param method - * the new string of the method value of this Message. * @param callId - * the new CallIdHeader object of the callId value of this * Message. * @param cSeq - * the new CSeqHeader object of the cSeq value of this Message. * @param from - * the new FromHeader object of the from value of this Message. * @param to - * the new ToHeader object of the to value of this Message. * @param via - * the new List object of the ViaHeaders of this Message. * @param contentType - * the new ContentTypeHeader object of the content type value of * this Message. * @param content - * the new byte array of the body content value of this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the method or the body. */ public Request createRequest(javax.sip.address.URI requestURI, String method, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, ContentTypeHeader contentType, byte[] content) throws ParseException { if (requestURI == null || method == null || callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException("missing parameters"); SIPRequest sipRequest = new SIPRequest(); sipRequest.setRequestURI(requestURI); sipRequest.setMethod(method); sipRequest.setCallId(callId); sipRequest.setCSeq(cSeq); sipRequest.setFrom(from); sipRequest.setTo(to); sipRequest.setVia(via); sipRequest.setMaxForwards(maxForwards); sipRequest.setContent(content, contentType); if (userAgent != null) { sipRequest.setHeader(userAgent); } return sipRequest; } /** * Creates a new Response message of type specified by the statusCode * paramater, containing the mandatory headers of the message with a body in * the form of a Java object and the body content type. * * @param statusCode * the new integer of the statusCode value of this Message. * @param callId * the new CallIdHeader object of the callId value of this * Message. * @param cSeq * the new CSeqHeader object of the cSeq value of this Message. * @param from * the new FromHeader object of the from value of this Message. * @param to * the new ToHeader object of the to value of this Message. * @param via * the new List object of the ViaHeaders of this Message. * @param contentType * the new ContentTypeHeader object of the content type value of * this Message. * @param content * the new Object of the body content value of this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, ContentTypeHeader contentType, Object content) throws ParseException { if (callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException("missing parameters"); SIPResponse sipResponse = new SIPResponse(); StatusLine statusLine = new StatusLine(); statusLine.setStatusCode(statusCode); String reason = SIPResponse.getReasonPhrase(statusCode); if (reason == null) throw new ParseException(statusCode + " Unknown", 0); statusLine.setReasonPhrase(reason); sipResponse.setStatusLine(statusLine); sipResponse.setCallId(callId); sipResponse.setCSeq(cSeq); sipResponse.setFrom(from); sipResponse.setTo(to); sipResponse.setVia(via); sipResponse.setContent(content, contentType); if ( userAgent != null) { sipResponse.setHeader(userAgent); } return sipResponse; } /** * Creates a new Response message of type specified by the statusCode * paramater, containing the mandatory headers of the message with a body in * the form of a byte array and the body content type. * * @param statusCode * the new integer of the statusCode value of this Message. * @param callId * the new CallIdHeader object of the callId value of this * Message. * @param cSeq * the new CSeqHeader object of the cSeq value of this Message. * @param from * the new FromHeader object of the from value of this Message. * @param to * the new ToHeader object of the to value of this Message. * @param via * the new List object of the ViaHeaders of this Message. * @param contentType * the new ContentTypeHeader object of the content type value of * this Message. * @param content * the new byte array of the body content value of this Message. * @throws ParseException * which signals that an error has been reached unexpectedly * while parsing the statusCode or the body. */ public Response createResponse(int statusCode, CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, List via, MaxForwardsHeader maxForwards, ContentTypeHeader contentType, byte[] content) throws ParseException { if (callId == null || cSeq == null || from == null || to == null || via == null || maxForwards == null || content == null || contentType == null) throw new NullPointerException("missing parameters"); SIPResponse sipResponse = new SIPResponse(); StatusLine statusLine = new StatusLine(); statusLine.setStatusCode(statusCode); String reason = SIPResponse.getReasonPhrase(statusCode); if (reason == null) throw new ParseException(statusCode + " : Unknown", 0); statusLine.setReasonPhrase(reason); sipResponse.setStatusLine(statusLine); sipResponse.setCallId(callId); sipResponse.setCSeq(cSeq); sipResponse.setFrom(from); sipResponse.setTo(to); sipResponse.setVia(via); sipResponse.setContent(content, contentType); if ( userAgent != null) { sipResponse.setHeader(userAgent); } return sipResponse; } /** * Create a request from a string. Conveniance method for UACs that want to * create an outgoing request from a string. Only the headers of the request * should be included in the String that is supplied to this method. * * @param requestString -- * string from which to create the message null string returns an * empty message. */ public javax.sip.message.Request createRequest(String requestString) throws java.text.ParseException { if (requestString == null || requestString.equals("")) { SIPRequest retval = new SIPRequest(); retval.setNullRequest(); return retval; } StringMsgParser smp = new StringMsgParser(); // smp.setStrict(this.strict); /* * This allows you to catch parse exceptions and create invalid messages * if you want. */ ParseExceptionListener parseExceptionListener = new ParseExceptionListener() { public void handleException(ParseException ex, SIPMessage sipMessage, Class headerClass, String headerText, String messageText) throws ParseException { // Rethrow the error for the essential headers. Otherwise bad // headers are simply // recorded in the message. if (testing) { if (headerClass == From.class || headerClass == To.class || headerClass == CallID.class || headerClass == MaxForwards.class || headerClass == Via.class || headerClass == RequestLine.class || headerClass == StatusLine.class || headerClass == CSeq.class) throw ex; sipMessage.addUnparsed(headerText); } } }; ParseExceptionListener exHandler = null; if (this.testing) exHandler = parseExceptionListener; SIPMessage sipMessage = smp.parseSIPMessage(requestString.getBytes(), true, this.strict, exHandler); if (!(sipMessage instanceof SIPRequest)) throw new ParseException(requestString, 0); return (SIPRequest) sipMessage; } /** * Create a response from a string * * @param responseString -- * string from which to create the message null string returns an * empty message. * */ public Response createResponse(String responseString) throws java.text.ParseException { if (responseString == null) return new SIPResponse(); StringMsgParser smp = new StringMsgParser(); SIPMessage sipMessage = smp.parseSIPMessage(responseString.getBytes(), true, false, null); if (!(sipMessage instanceof SIPResponse)) throw new ParseException(responseString, 0); return (SIPResponse) sipMessage; } /** * Set the common UserAgent header for all requests created from this message factory. * This header is applied to all Messages created from this Factory object except those * that take String for an argument and create Message from the given String. * * @param userAgent -- the user agent header to set. * * @since 2.0 */ public void setDefaultUserAgentHeader(UserAgentHeader userAgent) { MessageFactoryImpl.userAgent = userAgent; } /** * Set the common Server header for all responses created from this message factory. * This header is applied to all Messages created from this Factory object except those * that take String for an argument and create Message from the given String. * * @param userAgent -- the user agent header to set. * * @since 2.0 */ public void setDefaultServerHeader(ServerHeader server) { MessageFactoryImpl.server = server; } /** * Get the default common UserAgentHeader. * * @return the user agent header. * * @since 2.0 */ public static UserAgentHeader getDefaultUserAgentHeader() { return userAgent; } /** * Get the default common server header. * * @return the server header. */ public static ServerHeader getDefaultServerHeader() { return server; } /** * Set default charset used for encoding String content. * @param charset */ public void setDefaultContentEncodingCharset(String charset) throws NullPointerException, IllegalArgumentException { if (charset == null ) throw new NullPointerException ("Null argument!"); MessageFactoryImpl.defaultContentEncodingCharset = charset; } public static String getDefaultContentEncodingCharset() { return MessageFactoryImpl.defaultContentEncodingCharset; } public MultipartMimeContent createMultipartMimeContent(ContentTypeHeader multipartMimeCth, String[] contentType, String[] contentSubtype, String[] contentBody) { String boundary = multipartMimeCth.getParameter("boundary"); MultipartMimeContentImpl retval = new MultipartMimeContentImpl(multipartMimeCth); for (int i = 0 ; i < contentType.length; i++ ) { ContentTypeHeader cth = new ContentType(contentType[i],contentSubtype[i]); ContentImpl contentImpl = new ContentImpl(contentBody[i]); contentImpl.setContentTypeHeader(cth); retval.add(contentImpl); } return retval; } }