Source Code Cross Referenced for SipServerConnectionImpl.java in  » 6.0-JDK-Modules » j2me » gov » nist » microedition » sip » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » gov.nist.microedition.sip 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
003:         * Reserved.  Use is subject to license terms.
004:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005:         * 
006:         * This program is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU General Public License version
008:         * 2 only, as published by the Free Software Foundation.
009:         * 
010:         * This program is distributed in the hope that it will be useful, but
011:         * WITHOUT ANY WARRANTY; without even the implied warranty of
012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013:         * General Public License version 2 for more details (a copy is
014:         * included at /legal/license.txt).
015:         * 
016:         * You should have received a copy of the GNU General Public License
017:         * version 2 along with this work; if not, write to the Free Software
018:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019:         * 02110-1301 USA
020:         * 
021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022:         * Clara, CA 95054 or visit www.sun.com if you need additional
023:         * information or have any questions.
024:         */
025:        /*
026:         *   
027:         *
028:         * Created on Jan 29, 2004
029:         *
030:         */
031:        package gov.nist.microedition.sip;
032:
033:        import java.io.IOException;
034:        import java.io.InputStream;
035:        import java.io.InterruptedIOException;
036:        import java.io.OutputStream;
037:        import java.io.ByteArrayInputStream;
038:
039:        import java.util.Vector;
040:        import java.util.Enumeration;
041:
042:        import javax.microedition.sip.SipDialog;
043:        import javax.microedition.sip.SipException;
044:        import javax.microedition.sip.SipServerConnection;
045:        import javax.microedition.sip.SipConnection;
046:
047:        import gov.nist.core.HostPort;
048:        import gov.nist.core.ParseException;
049:        import gov.nist.siplite.SIPConstants;
050:        import gov.nist.siplite.SipStack;
051:        import gov.nist.siplite.SipProvider;
052:        import gov.nist.siplite.TransactionAlreadyExistsException;
053:        import gov.nist.siplite.TransactionUnavailableException;
054:        import gov.nist.siplite.message.*;
055:        import gov.nist.siplite.stack.Dialog;
056:        import gov.nist.siplite.stack.ServerTransaction;
057:        import gov.nist.siplite.stack.Subscription;
058:        import gov.nist.siplite.header.ContactHeader;
059:        import gov.nist.siplite.header.ContactList;
060:        import gov.nist.siplite.header.ExpiresHeader;
061:        import gov.nist.siplite.header.Header;
062:        import gov.nist.siplite.header.HeaderList;
063:        import gov.nist.siplite.header.ToHeader;
064:        import gov.nist.siplite.header.SubscriptionStateHeader;
065:        import gov.nist.siplite.header.ContentLengthHeader;
066:        import gov.nist.siplite.address.*;
067:        import gov.nist.siplite.stack.Transaction;
068:
069:        import com.sun.midp.log.Logging;
070:        import com.sun.midp.log.LogChannels;
071:
072:        /**
073:         * SIP ServerConnection implementation.
074:         *
075:         * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
076:         */
077:        public class SipServerConnectionImpl implements  SipServerConnection {
078:            // Server Transaction States
079:            /**
080:             * Terminated, the final state, in which the SIP connection has
081:             * been terminated by error or closed
082:             */
083:            public static final int TERMINATED = 0;
084:            /**
085:             * Request Received, SipServerConnection returned from
086:             * SipConnectionNotifier or provisional response(s) (1xx) sent.
087:             */
088:            public static final int REQUEST_RECEIVED = 1;
089:            /**
090:             * Initialized, response initialized calling initResponse()
091:             */
092:            public static final int INITIALIZED = 2;
093:            /**
094:             * Stream Open, OutputStream opened with openContentOutputStream().
095:             * Opening InputStream for received request does not trigger state
096:             * transition.
097:             */
098:            public static final int STREAM_OPEN = 3;
099:            /**
100:             * Completed, transaction completed with sending final response
101:             * (2xx, 3xx, 4xx, 5xx, 6xx)
102:             */
103:            public static final int COMPLETED = 4;
104:            /**
105:             * Attribute keeping the actual state of this server transaction
106:             */
107:            private int state;
108:            /**
109:             * the sip dialog this client transaction belongs to
110:             */
111:            private SipDialog sipDialog = null;
112:            /**
113:             * the request for this server transaction
114:             */
115:            private Request request = null;
116:            /**
117:             * the response to the actual request
118:             */
119:            private Response response = null;
120:            /**
121:             * content of the response body
122:             */
123:            private SDPOutputStream contentOutputStream = null;
124:            /**
125:             * content from the request body
126:             */
127:            private InputStream contentInputStream = null;
128:
129:            /**
130:             * Receiver of incoming messages
131:             */
132:            private SipConnectionNotifierImpl sipConnectionNotifierImpl;
133:            /**
134:             * Flag indicating which SIP message (request or response)
135:             * should be used in getHeader()/getHeaders()/setHeader()/removeHeader().
136:             */
137:            private boolean useResponse = false;
138:
139:            /**
140:             * Boolean flag used to indicate if 2xx is allowed to resend
141:             * This flag is set to true if 2xx is sent and SipServerConnectionImpl
142:             * transitions to COMPLETED state
143:             */
144:            private boolean resend2xxAllowed = false;
145:
146:            /**
147:             * Constructor.
148:             * @param request the protocol connection request
149:             * @param sipDialog the current transaction state
150:             * @param sipConnectionNotifierImpl the notification handler
151:             */
152:            protected SipServerConnectionImpl(Request request,
153:                    SipDialog sipDialog,
154:                    SipConnectionNotifierImpl sipConnectionNotifierImpl) {
155:                this .request = request;
156:                this .sipDialog = sipDialog;
157:                this .sipConnectionNotifierImpl = sipConnectionNotifierImpl;
158:                if (request.getMethod() == Request.ACK) {
159:                    state = COMPLETED;
160:                } else {
161:                    state = REQUEST_RECEIVED;
162:                }
163:            }
164:
165:            /**
166:             * Initializes SipServerConnection with a specific SIP response to the
167:             * received request.
168:             * The default headers and reason phrase will be initialized automatically.
169:             * After this the SipServerConnection is in Initialized state.
170:             * The response can be sent. The procedure of generating the response and
171:             * header fields is defined in RFC 3261 [1] p. 49-50. At least following
172:             * information is set by the method:
173:             * From MUST equal the From header field of the request
174:             * Call-ID  MUST equal the Call-ID header field of the request
175:             * CSeq MUST equal the CSeq field of the request
176:             * Via MUST equal the Via header field values in the request
177:             * and MUST maintain the same ordering
178:             * To MUST Copy if exists in the original request,
179:             * 'tag' MUST be added if not present
180:             * Furthermore, if the system has automatically sent the 100 Trying
181:             * response, the 100 response initialized and sent by the user
182:             *  is just ignored.
183:             * @param code - Response status code 1xx - 6xx
184:             * @throws IllegalArgumentException - if the status code is out of
185:             * range 100-699 (RFC 3261 p.28-29)
186:             * @throws SipException - INVALID_STATE if the response can not be
187:             * initialized, because of wrong state.
188:             */
189:            public void initResponse(int code) throws IllegalArgumentException,
190:                    SipException {
191:                // Check if the code is not out of range
192:                if (code < 100 || code > 699)
193:                    throw new IllegalArgumentException(
194:                            "the response code is out of range.");
195:
196:                // Check if we are in a good state to init the response
197:                if (state != REQUEST_RECEIVED)
198:                    throw new SipException(
199:                            "the response can not be initialized,"
200:                                    + " because of wrong state.",
201:                            SipException.INVALID_STATE);
202:
203:                // Generating the response to the request
204:                try {
205:                    response = StackConnector.messageFactory.createResponse(
206:                            code, request);
207:                } catch (ParseException pe) {
208:                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
209:                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
210:                                "Exception in SSC.initResponse(): " + pe);
211:                        pe.printStackTrace();
212:                    }
213:                }
214:
215:                // Set the toTag in the ToHeader if not already present
216:                ToHeader toHeader = (ToHeader) response
217:                        .getHeader(ToHeader.NAME);
218:                if (toHeader.getTag() == null)
219:                    toHeader.setTag(StackConnector.generateTag());
220:
221:                // if we don't have any contact headers we add one
222:                ContactList contactList = response.getContactHeaders();
223:                if (contactList == null || contactList.isEmpty()) {
224:                    ContactHeader contactHeader = null;
225:                    String transport = sipConnectionNotifierImpl
226:                            .getSipProvider().getListeningPoint()
227:                            .getTransport();
228:                    try {
229:                        Address address = StackConnector.addressFactory
230:                                .createAddress("<sip:"
231:                                        + sipConnectionNotifierImpl
232:                                                .getLocalAddress()
233:                                        + ":"
234:                                        + sipConnectionNotifierImpl
235:                                                .getLocalPort() + ";transport="
236:                                        + transport + ">");
237:                        contactHeader = StackConnector.headerFactory
238:                                .createContactHeader(address);
239:                        response.addHeader(contactHeader);
240:                    } catch (IOException ioe) {
241:                        ioe.printStackTrace();
242:                    } catch (ParseException pe) {
243:                        pe.printStackTrace();
244:                    }
245:                }
246:
247:                state = INITIALIZED;
248:                useResponse = true;
249:
250:                // System.out.println("The following response has been initialized:\n"+
251:                //                    response.toString());
252:            }
253:
254:            /**
255:             * Changes the default reason phrase.
256:             * @param phrase the default reason phrase.
257:             * @throws SipException INVALID_STATE if the response can not
258:             * be initialized, because of wrong state.
259:             * INVALID_OPERATION if the reason phrase can not be set.
260:             * @throws IllegalArgumentException if the reason phrase is illegal.
261:             */
262:            public void setReasonPhrase(String phrase) throws SipException,
263:                    IllegalArgumentException {
264:                if (state != INITIALIZED)
265:                    throw new SipException("the Reason Phrase can not be set,"
266:                            + " because of wrong state.",
267:                            SipException.INVALID_STATE);
268:
269:                if (phrase == null) {
270:                    throw new IllegalArgumentException(
271:                            "The reason phrase can not be null.");
272:                }
273:
274:                // RFC 3261, section 7.2: No CR or LF is allowed
275:                // (in the Status Line) except in the final CRLF sequence.
276:                if ((phrase.indexOf("\n") != -1)
277:                        || (phrase.indexOf("\r") != -1)) {
278:                    throw new IllegalArgumentException("Invalid reason phrase.");
279:                }
280:
281:                response.setReasonPhrase(phrase);
282:            }
283:
284:            /**
285:             * (non-Javadoc)
286:             * @see javax.microedition.sip.SipConnection#send()
287:             */
288:            public void send() throws IOException, InterruptedIOException,
289:                    SipException {
290:                if (state == REQUEST_RECEIVED) {
291:                    throw new SipException("can not send response"
292:                            + " because of wrong state.",
293:                            SipException.INVALID_STATE);
294:                }
295:
296:                if ((state == COMPLETED) && !resend2xxAllowed) {
297:                    throw new SipException("COMPLETED state allows"
298:                            + " only resend of 2xx responses",
299:                            SipException.INVALID_STATE);
300:                }
301:
302:                if (state == TERMINATED) {
303:                    throw new SipException("can not send response"
304:                            + " because SipServerConnection is TERMINATED",
305:                            SipException.INVALID_STATE);
306:                }
307:
308:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
309:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
310:                            "Actual request for the response we want to send:\n"
311:                                    + request.toString());
312:                }
313:
314:                ServerTransaction serverTransaction = (ServerTransaction) request
315:                        .getTransaction();
316:
317:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
318:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
319:                            "SipServerTransaction :" + serverTransaction);
320:                }
321:
322:                // Set the sdp body of the message
323:                if (contentOutputStream != null) {
324:                    contentOutputStream.setOpen(false);
325:                    response.setContent(contentOutputStream
326:                            .getByteArrayOutputStream().toByteArray());
327:                    contentOutputStream = null;
328:                }
329:
330:                String method = request.getMethod();
331:                final int statusCode = response.getStatusCode();
332:                final int statusGroup = statusCode / 100;
333:
334:                // send the response
335:                if (!resend2xxAllowed) { // don't create new transaction on resending
336:                    SipStack sipStack = sipConnectionNotifierImpl
337:                            .getStackConnector().getSipStack();
338:
339:                    if (serverTransaction == null
340:                            || sipStack.isDialogCreated(method)) {
341:                        try {
342:                            SipProvider sipProvider = sipConnectionNotifierImpl
343:                                    .getSipProvider();
344:                            if (serverTransaction == null) {
345:                                serverTransaction = sipProvider
346:                                        .getNewServerTransaction(request);
347:                            } else {
348:                                /*
349:                                 * 12.1 Creation of a Dialog
350:                                 * Dialogs are created through the generation of
351:                                 * non-failure responses to requests with specific
352:                                 * methods.  Within this specification, only 2xx and
353:                                 * 101-199 responses with a To tag, where the request
354:                                 * was INVITE, will establish a dialog.
355:                                 */
356:                                if (statusCode > 100 && statusCode < 300) {
357:                                    // Equip a dialog in case of dialog is null
358:                                    // or its state is INITIALIZED only prevent
359:                                    // changing contact property of dialog by
360:                                    // sending 200 OK response for INVITE
361:                                    // after sending 200 OK for UPDATE
362:                                    boolean equipDialog = false;
363:                                    if (sipDialog == null) {
364:                                        equipDialog = true;
365:                                    } else if (sipDialog.getState() == Dialog.INITIAL_STATE) {
366:                                        equipDialog = true;
367:                                    }
368:
369:                                    if (equipDialog) {
370:                                        sipProvider.equipADialogForTransaction(
371:                                                serverTransaction, request);
372:                                    }
373:                                } else if ((sipDialog != null)
374:                                        && (statusGroup > 2 && statusGroup < 7)) {
375:                                    // JSR180, p.42
376:                                    // Terminated state: error response (3xx-6xx)
377:                                    // received (or sent).
378:                                    ((SipDialogImpl) sipDialog)
379:                                            .setState(SipDialog.TERMINATED);
380:                                }
381:                            }
382:                        } catch (TransactionAlreadyExistsException taee) {
383:                            if (Logging.REPORT_LEVEL <= Logging.ERROR) {
384:                                Logging.report(Logging.ERROR,
385:                                        LogChannels.LC_JSR180,
386:                                        "Exception in SSC.send(): " + taee);
387:                                taee.printStackTrace();
388:                            }
389:                            // return;
390:                        } catch (TransactionUnavailableException tue) {
391:                            if (Logging.REPORT_LEVEL <= Logging.ERROR) {
392:                                Logging.report(Logging.ERROR,
393:                                        LogChannels.LC_JSR180,
394:                                        "Exception in SSC.send(): " + tue);
395:                                tue.printStackTrace();
396:                            }
397:                            // return;
398:                        }
399:                    }
400:                }
401:
402:                SipConnectionNotifierImpl newNotifier = sipConnectionNotifierImpl;
403:
404:                if (sipDialog != null) {
405:                    Dialog dialog = ((SipDialogImpl) sipDialog).getDialog();
406:
407:                    if (dialog != null
408:                            && (statusCode > 199 && statusCode < 300)) {
409:                        if (method.equals(Request.UPDATE)) {
410:                            // processing UPDATE - change dialog contact property
411:                            dialog.addRoute(serverTransaction
412:                                    .getOriginalRequest());
413:                        }
414:
415:                        newNotifier = findNotifier();
416:                        Transaction transaction = (Transaction) dialog
417:                                .getFirstTransaction();
418:                        if (transaction instanceof  ServerTransaction) {
419:                            transaction.setApplicationData(newNotifier);
420:                        }
421:
422:                        if (newNotifier != null) {
423:                            sipConnectionNotifierImpl = newNotifier;
424:                        }
425:                    }
426:                }
427:
428:                // Set the application data so that when the request comes in,
429:                // it will retrieve this SipConnectionNotifier
430:                serverTransaction.setApplicationData(newNotifier);
431:
432:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
433:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
434:                            "response to send : " + response);
435:                }
436:
437:                // May throw IOException and SipException
438:                serverTransaction.sendResponse(response);
439:
440:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
441:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
442:                            "response sent");
443:                }
444:
445:                // Change the state of SipServerConnection
446:                int responseClass = response.getStatusCode() / 100;
447:                if (responseClass == 1) { // 1xx responses
448:                    state = REQUEST_RECEIVED;
449:                } else {
450:                    state = COMPLETED;
451:                    if (responseClass == 2) {
452:                        // Allow 2xx response to be resent
453:                        resend2xxAllowed = true;
454:                    }
455:                }
456:
457:                // Change the dialog state
458:                changeDialogState(serverTransaction);
459:            }
460:
461:            /**
462:             * Finds a connection notifier that listens on the port given in the
463:             * Contact header of the response. When a 2xx response contains a new
464:             * Contact with the port that is different from one that is used by the
465:             * connection notifier associated with this server connection object
466:             * (sipConnectionNotifierImpl), the notifier must be changed accordingly.
467:             * @returns SipConnectionNotifier listening on the new Contact or
468:             * null if such notifier was not found.
469:             */
470:            private SipConnectionNotifierImpl findNotifier()
471:                    throws SipException {
472:                // IMPL_NOTE: handle shared connections
473:                int localPort = SIPConstants.DEFAULT_NONTLS_PORT;
474:                String localTransport = SIPConstants.TRANSPORT_UDP;
475:
476:                ContactList contactList = response.getContactHeaders();
477:                if (contactList != null) {
478:                    ContactHeader contact = (ContactHeader) contactList
479:                            .getFirst();
480:                    HostPort hp = contact.getHostPort();
481:                    if (hp != null) {
482:                        localPort = hp.getPort();
483:                    }
484:
485:                    URI uri = contact.getAddress().getURI();
486:                    String transport = uri.isSipURI() ? ((SipURI) uri)
487:                            .getTransportParam() : null;
488:                    if (transport != null) {
489:                        localTransport = transport;
490:                    }
491:                }
492:
493:                // Find a SipConnectionNotifier listening on the given port.
494:                StackConnector stackConnector = sipConnectionNotifierImpl
495:                        .getStackConnector();
496:
497:                SipConnectionNotifierImpl newNotifier = (SipConnectionNotifierImpl) stackConnector
498:                        .getSipConnectionNotifier(localPort,
499:                                sipConnectionNotifierImpl.getMIMEType());
500:
501:                return newNotifier;
502:            }
503:
504:            /**
505:             * Sets header value in SIP message. If the header does not exist
506:             * it will be added to the message, otherwise the existing header is
507:             * overwritten. If multiple header field values exist the topmost is
508:             * overwritten. The implementations MAY restrict the access to some headers
509:             * according to RFC 3261.
510:             * @param name - name of the header, either in full or compact form.
511:             * RFC 3261 p.32
512:             * @param value - the header value
513:             * @throws SipException - INVALID_STATE if header can not be set in
514:             * this state. <br> INVALID_OPERATION if the system does not allow to set
515:             * this header.
516:             * @throws IllegalArgumentException - MAY be thrown if the header or
517:             * value is invalid
518:             */
519:            public void setHeader(String name, String value)
520:                    throws SipException, IllegalArgumentException {
521:                if (state != INITIALIZED)
522:                    throw new SipException("the Header can not be set,"
523:                            + " because of wrong state.",
524:                            SipException.INVALID_STATE);
525:
526:                if (name == null)
527:                    throw new IllegalArgumentException(
528:                            "The header name can not be null");
529:
530:                if (value == null)
531:                    throw new IllegalArgumentException(
532:                            "The header value can not be null");
533:
534:                Header header = null;
535:
536:                try {
537:                    header = StackConnector.headerFactory.createHeader(name,
538:                            value);
539:                } catch (ParseException pe) {
540:                    throw new IllegalArgumentException(pe.getMessage());
541:                }
542:
543:                if (header == null)
544:                    throw new IllegalArgumentException("null header!");
545:
546:                // response.attachHeader(header, false, true);
547:                Message currentMessage = useResponse ? (Message) response
548:                        : (Message) request;
549:
550:                if (currentMessage == null) {
551:                    throw new SipException("Failure in setHeader(),"
552:                            + " associated request or response is null",
553:                            SipException.INVALID_MESSAGE);
554:                }
555:
556:                currentMessage.attachHeader(header, true, true);
557:            }
558:
559:            /**
560:             * Adds a header to the SIP message. If multiple header field values exist
561:             * the header value is added topmost of this type of headers.
562:             * The implementations MAY restrict the access to some headers
563:             * according to RFC 3261.
564:             * @param name - name of the header, either in full or compact form.
565:             * RFC 3261 p.32
566:             * @param value - the header value
567:             * @throws SipException - INVALID_STATE if header can not be added in
568:             * this state. <br> INVALID_OPERATION if the system does not allow to add
569:             * this header.
570:             * @throws IllegalArgumentException - MAY be thrown if the header or
571:             * value is invalid
572:             */
573:            public void addHeader(String name, String value)
574:                    throws SipException, IllegalArgumentException {
575:                if (state != INITIALIZED)
576:                    throw new SipException("the Header can not be add,"
577:                            + " because of wrong state.",
578:                            SipException.INVALID_STATE);
579:                if (name == null)
580:                    throw new IllegalArgumentException(
581:                            "The header name can not be null");
582:                if (value == null)
583:                    throw new IllegalArgumentException(
584:                            "The header value can not be null");
585:
586:                Header header = null;
587:                try {
588:                    header = StackConnector.headerFactory.createHeader(name,
589:                            value);
590:                } catch (ParseException pe) {
591:                    throw new IllegalArgumentException(
592:                            "The header can not be created,"
593:                                    + " check if it is correct");
594:                }
595:
596:                Message currentMessage = useResponse ? (Message) response
597:                        : (Message) request;
598:
599:                if (currentMessage == null) {
600:                    throw new SipException("Failure in addHeader(),"
601:                            + " associated request or response is null",
602:                            SipException.INVALID_MESSAGE);
603:                }
604:
605:                currentMessage.addHeader(header);
606:            }
607:
608:            /**
609:             * Removes header from the SIP message. If multiple header field
610:             * values exist the topmost is removed.
611:             * The implementations MAY restrict the access to some headers
612:             * according to RFC 3261.
613:             * If the named header is not found this method does nothing.
614:             * @param name - name of the header to be removed, either int
615:             * full or compact form RFC 3261 p.32.
616:             * @throws SipException - INVALID_STATE if header can not be removed in
617:             * this state. <br> INVALID_OPERATION if the system does not allow to remove
618:             * this header.
619:             */
620:            public void removeHeader(String name) throws SipException,
621:                    IllegalArgumentException {
622:                if (state != INITIALIZED) {
623:                    throw new SipException("the Header can not be removed,"
624:                            + " because of wrong state.",
625:                            SipException.INVALID_STATE);
626:                }
627:
628:                if (name == null) {
629:                    throw new IllegalArgumentException(
630:                            "The header name can not be null");
631:                }
632:
633:                Message currentMessage = useResponse ? (Message) response
634:                        : (Message) request;
635:
636:                if (currentMessage == null) {
637:                    throw new SipException("Failure in removeHeader(),"
638:                            + " associated request or response is null",
639:                            SipException.INVALID_MESSAGE);
640:                }
641:
642:                currentMessage.removeHeader(name, true);
643:            }
644:
645:            /**
646:             * Gets the header field value(s) of specified header type
647:             * @param name - name of the header, either in full or compact form.
648:             * RFC 3261 p.32
649:             * @return array of header field values (topmost first), or null if the
650:             * current message does not have such a header or the header is for other
651:             * reason not available (e.g. message not initialized).
652:             */
653:            public String[] getHeaders(String name) {
654:                Message currentMessage = useResponse ? (Message) response
655:                        : (Message) request;
656:
657:                // Return null if associated request or response is null
658:                if (currentMessage == null) {
659:                    return null;
660:                }
661:
662:                HeaderList nameList = currentMessage.getHeaderList(name);
663:
664:                if (nameList == null) {
665:                    return null;
666:                }
667:
668:                int size = nameList.size();
669:
670:                if (size < 1) {
671:                    return null;
672:                }
673:
674:                String[] headerValues = new String[size];
675:
676:                for (int count = 0; count < size; count++) {
677:                    headerValues[count] = ((Header) nameList.elementAt(count))
678:                            .getHeaderValue();
679:                }
680:
681:                return headerValues;
682:            }
683:
684:            /**
685:             * Gets the header field value of specified header type.
686:             * @param name - name of the header type, either in full or compact form.
687:             * RFC 3261 p.32
688:             * @return topmost header field value, or null if the
689:             * current message does not have such a header or the header is for other
690:             * reason not available (e.g. message not initialized).
691:             */
692:            public String getHeader(String name) {
693:                Message currentMessage = useResponse ? (Message) response
694:                        : (Message) request;
695:
696:                // Return null if associated request or response is null
697:                if (currentMessage == null) {
698:                    return null;
699:                }
700:
701:                Header header = currentMessage.getHeader(name);
702:
703:                if (header == null) {
704:                    return null;
705:                }
706:
707:                return header.getHeaderValue();
708:            }
709:
710:            /**
711:             * Gets the SIP method. Applicable when a message has been
712:             * initialized or received.
713:             * @return SIP method name REGISTER, INVITE, NOTIFY, etc. Returns null if
714:             * the method is not available.
715:             */
716:            public String getMethod() {
717:                if (TERMINATED == state) {
718:                    return null;
719:                } else {
720:                    return request.getMethod();
721:                }
722:            }
723:
724:            /**
725:             * Gets Request-URI. Available when SipClientConnection is in Initialized
726:             * state or when SipServerConnection is in Request Received state.
727:             * Built from the original URI given in Connector.open().
728:             * See RFC 3261 p.35 (8.1.1.1 Request-URI)
729:             * @return Request-URI of the message. Returns null if the Request-URI
730:             * is not available.
731:             */
732:            public String getRequestURI() {
733:                // from the JSR180 spec:
734:                // "Returns null if the Request-URI is not available...
735:                // Available when... SipServerConnection is in Request Received state."
736:                // Most likely, because only in this case there's no ambiguity whether
737:                // the request or the response was meant.
738:                if (REQUEST_RECEIVED != state) {
739:                    return null;
740:                } else {
741:                    return request.getRequestURI().toString();
742:                }
743:            }
744:
745:            /**
746:             * Gets SIP response status code. Available when SipClientConnection is in
747:             * Proceeding or Completed state or when SipServerConnection is in
748:             * Initialized state.
749:             * @return status code 1xx, 2xx, 3xx, 4xx, ... Returns 0 if the status code
750:             * is not available.
751:             */
752:            public int getStatusCode() {
753:                if (state != INITIALIZED || response == null) {
754:                    return 0;
755:                } else {
756:                    return response.getStatusCode();
757:                }
758:            }
759:
760:            /**
761:             * Gets SIP response reason phrase. Available when SipClientConnection is in
762:             * Proceeding or Completed state or when SipServerConnection is in
763:             * Initialized state.
764:             * @return reason phrase. Returns null if the reason phrase is
765:             *  not available.
766:             */
767:            public String getReasonPhrase() {
768:                if (state != INITIALIZED || response == null) {
769:                    return null;
770:                } else {
771:                    return response.getReasonPhrase();
772:                }
773:            }
774:
775:            /**
776:             * Returns the current SIP dialog. This is available when the SipConnection
777:             * belongs to a created SipDialog and the system has received (or sent)
778:             * provisional (101-199) or final response (200).
779:             * @return SipDialog object if this connection belongs to a dialog,
780:             * otherwise returns null.
781:             */
782:            public SipDialog getDialog() {
783:                if (sipDialog != null) {
784:                    byte dialogState = this .sipDialog.getState();
785:                    if ((dialogState != SipDialog.EARLY)
786:                            && (dialogState != SipDialog.CONFIRMED)) {
787:                        return null;
788:                    }
789:                }
790:
791:                return sipDialog;
792:            }
793:
794:            /**
795:             * Returns InputStream to read SIP message body content.
796:             * @return InputStream to read body content
797:             * @throws java.io.IOException - if the InputStream can not be opened,
798:             * because of an I/O error occurred.
799:             * @throws SipException - INVALID_STATE the InputStream can not be opened
800:             * in this state (e.g. no message received).
801:             */
802:            public InputStream openContentInputStream() throws IOException,
803:                    SipException {
804:                if (state != REQUEST_RECEIVED)
805:                    throw new SipException(
806:                            "the content input stream can not be open,"
807:                                    + " because of wrong state: " + state,
808:                            SipException.INVALID_STATE);
809:
810:                if (request == null) {
811:                    throw new IOException("Request is null.");
812:                }
813:
814:                ContentLengthHeader contentLengthHeader = request
815:                        .getContentLengthHeader();
816:                if (contentLengthHeader == null) {
817:                    throw new IOException(
818:                            "Request contains no content length header.");
819:                }
820:
821:                int bodyLength = contentLengthHeader.getContentLength();
822:                if (bodyLength == 0) {
823:                    throw new IOException("Request's body has zero length.");
824:                }
825:
826:                byte[] buf = request.getRawContent();
827:                if (buf == null) { // body is empty
828:                    throw new IOException("Body of SIP request is empty.");
829:                }
830:
831:                contentInputStream = new ByteArrayInputStream(buf);
832:                return contentInputStream;
833:            }
834:
835:            /**
836:             * Returns OutputStream to fill the SIP message body content.
837:             * When calling close() on OutputStream the message will be sent
838:             * to the network. So it is equivalent to call send(). Again send() must
839:             * not be called after closing the OutputStream, since it will throw
840:             * Exception because of calling the method in wrong state.
841:             * Before opening OutputStream the Content-Length and Content-Type headers
842:             * has to se set. If not SipException.UNKNOWN_LENGTH or
843:             * SipException.UNKNOWN_TYPE will be thrown respectively.
844:             * @return OutputStream to write body content
845:             * @throws IOException if the OutputStream can not be opened,
846:             * because of an I/O error occurred.
847:             * @throws SipException INVALID_STATE the OutputStream can not be opened
848:             * in this state (e.g. no message initialized).
849:             * UNKNOWN_LENGTH Content-Length header not set.
850:             * UNKNOWN_TYPE Content-Type header not set.
851:             */
852:            public OutputStream openContentOutputStream() throws IOException,
853:                    SipException {
854:                if (state != INITIALIZED)
855:                    throw new SipException(
856:                            "the content output strean can not be open,"
857:                                    + " because of wrong state.",
858:                            SipException.INVALID_STATE);
859:                if (state == TERMINATED) {
860:                    throw new IOException("can not open content output stream"
861:                            + " because SipServerConnection is TERMINATED");
862:                }
863:
864:                if (response.getHeader(Header.CONTENT_TYPE) == null)
865:                    throw new SipException("Content-Type unknown, set the"
866:                            + " content-type header first",
867:                            SipException.UNKNOWN_TYPE);
868:                if (response.getHeader(Header.CONTENT_LENGTH) == null)
869:                    throw new SipException("Content-Length unknown, set the "
870:                            + "content-length header first",
871:                            SipException.UNKNOWN_LENGTH);
872:                contentOutputStream = new SDPOutputStream(this );
873:                state = STREAM_OPEN;
874:                return contentOutputStream;
875:            }
876:
877:            /**
878:             * Closes the connection.
879:             * @exception IOException if an I/O error occurs
880:             * @see javax.microedition.io.Connection#close()
881:             */
882:            public void close() throws IOException {
883:                state = TERMINATED;
884:            }
885:
886:            /**
887:             * Change the state of the dialog after sending a response.
888:             * @param serverTransaction current transaction
889:             */
890:            private void changeDialogState(ServerTransaction serverTransaction) {
891:                // System.out.println(">>> SERVER: changing state, " +
892:                //     response.getCSeqHeader().getMethod());
893:
894:                int statusCode = response.getStatusCode();
895:
896:                if (statusCode == 100 || sipDialog == null) {
897:                    return;
898:                }
899:
900:                String cseqMethod = response.getCSeqHeader().getMethod();
901:                SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
902:
903:                if (cseqMethod.equals(Request.NOTIFY)) {
904:                    // System.out.println(">>> SERVER: NOTIFY!!!");
905:                    sipDialogImpl.handleNotify(request, serverTransaction
906:                            .getDialog(), null);
907:                    return;
908:                }
909:
910:                // Default is to not create a dialog.
911:                // The dialog only is created for the methods that are known
912:                // to establish a dialog.
913:                int statusGroup = statusCode / 100;
914:
915:                if (sipConnectionNotifierImpl.getStackConnector().getSipStack()
916:                        .isDialogCreated(cseqMethod)
917:                        || cseqMethod.equals(Request.BYE)) {
918:                    if (statusGroup == 2) {
919:                        // RFC 3261, section 13.2.2.4:
920:                        // If the dialog identifier in the 2xx response matches the
921:                        // dialog identifier of an existing dialog, the dialog MUST
922:                        // be transitioned to the "confirmed" state.
923:                        sipDialogImpl.setDialog(serverTransaction.getDialog());
924:                        sipDialogImpl.setState(SipDialog.CONFIRMED);
925:
926:                        if (statusCode == 200) {
927:                            if (cseqMethod.equals(Request.SUBSCRIBE)
928:                                    || cseqMethod.equals(Request.REFER)) {
929:                                sipDialogImpl.addSubscription(new Subscription(
930:                                        sipDialogImpl.getDialog(), request));
931:                            } else if (cseqMethod.equals(Request.BYE)) {
932:                                sipDialogImpl.setWaitForBye(false);
933:                                sipDialogImpl.terminateIfNoSubscriptions();
934:                            }
935:                        }
936:                    } else if (statusGroup == 1) {
937:                        // provisional response
938:                        if (sipDialog.getState() == SipDialogImpl.INITIALIZED) {
939:                            // switch to EARLY state
940:                            sipDialogImpl.setState(SipDialog.EARLY);
941:                        }
942:                    } else { // another response code - switch to TERMINATED state
943:                        sipDialogImpl.terminateIfNoSubscriptions();
944:                    }
945:
946:                    // set dialog ID if need
947:                    if (sipDialogImpl.getDialogID() == null) {
948:                        int state = sipDialog.getState();
949:                        if ((state == SipDialog.EARLY)
950:                                || (state == SipDialog.CONFIRMED)) {
951:                            sipDialogImpl.setDialog(serverTransaction
952:                                    .getDialog());
953:                            sipDialogImpl.setDialogID(response
954:                                    .getDialogId(true));
955:                        }
956:                    }
957:                }
958:            }
959:
960:            /**
961:             * Return the state of SIP server connection
962:             *
963:             * @return state of the SIP Server Connection
964:             */
965:            public int getState() {
966:                return state;
967:            }
968:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.