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: * RefreshTask.java
027: *
028: * Created on Apr 8, 2004
029: *
030: */
031: package gov.nist.microedition.sip;
032:
033: import gov.nist.core.ParseException;
034: import gov.nist.siplite.header.Header;
035: import gov.nist.siplite.header.CallIdHeader;
036: import gov.nist.siplite.header.CSeqHeader;
037: import gov.nist.siplite.header.ViaHeader;
038: import gov.nist.siplite.message.Request;
039:
040: import java.io.OutputStream;
041: import java.io.IOException;
042: import java.io.InterruptedIOException;
043: import java.util.TimerTask;
044: import java.util.Vector;
045:
046: import javax.microedition.sip.SipClientConnection;
047: import javax.microedition.sip.SipConnectionNotifier;
048: import javax.microedition.sip.SipException;
049: import javax.microedition.sip.SipRefreshListener;
050:
051: import com.sun.midp.log.Logging;
052: import com.sun.midp.log.LogChannels;
053:
054: /**
055: * Refreshs the transaction state.
056: *
057: * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
058: */
059: public class RefreshTask extends TimerTask {
060: /** The current request to be processed. */
061: private Request request = null;
062: /** The associated connection client. */
063: private SipClientConnection sipClientConnection = null;
064: /** The connection state notifier. */
065: private SipConnectionNotifier sipConnectionNotifier = null;
066: /** The current refresh event listener. */
067: private SipRefreshListener sipRefreshListener;
068: /** The task identifier. */
069: private String taskId;
070:
071: /**
072: * Creates a new instance of RefreshTask
073: * @param id the task identifier
074: * @param rq the request to resend
075: * @param scn the connection used to send the request
076: * @param listener the callback interface used listening for
077: * refresh event on this task
078: * @param scc the connection to update
079: */
080: public RefreshTask(String id, Request rq,
081: SipConnectionNotifier scn, SipRefreshListener listener,
082: SipClientConnection scc) {
083: taskId = id;
084: request = rq;
085: sipConnectionNotifier = scn;
086: sipRefreshListener = listener;
087: sipClientConnection = scc;
088: }
089:
090: /**
091: * Run the refresh thread.
092: * @see java.lang.Runnable#run()
093: */
094: public void run() {
095: Request clonedRequest = (Request) request.clone();
096: // setRequestHeaders(clonedRequest);
097: request = null;
098:
099: try {
100: updateAndSendRequest(clonedRequest);
101: } catch (Exception ex) {
102: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
103: Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
104: "RefreshTask.run(): can't send a message: "
105: + ex);
106: }
107: }
108: }
109:
110: /**
111: * Sets appropriate CSeq and Via headers in the given request
112: * preparing it for sending.
113: * @param clonedRequest the request to modify
114: */
115: public synchronized void setRequestHeaders(Request clonedRequest) {
116: // RFC 3261, section 10.2.4, Refreshing Bindings:
117: // "A UA SHOULD use the same Call-ID for all registrations during a
118: // single boot cycle".
119: //
120: // Call-Id header was added in SipClientConnectionImpl.send()
121: // when the initial request was sent. This is the reason why
122: // Call-Id header is not added here.
123:
124: // Update the CSeq header. RFC 3261, p. 58:
125: // A UA MUST increment the CSeq value by one for each
126: // REGISTER request with the same Call-ID.
127: CSeqHeader cseq = clonedRequest.getCSeqHeader();
128:
129: if (cseq != null) {
130: cseq.setSequenceNumber(cseq.getSequenceNumber() + 1);
131: } else {
132: // log an error
133: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
134: Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
135: "RefreshTask.run(): The request doesn't "
136: + "contain CSeq header!");
137: }
138: }
139:
140: // ViaHeader
141: clonedRequest.removeHeader(ViaHeader.NAME);
142:
143: Vector viaHeaders = new Vector();
144: try {
145: ViaHeader viaHeader = StackConnector.headerFactory
146: .createViaHeader(
147: sipConnectionNotifier.getLocalAddress(),
148: sipConnectionNotifier.getLocalPort(),
149: ((SipConnectionNotifierImpl) sipConnectionNotifier)
150: .getSipProvider()
151: .getListeningPoint().getTransport(),
152: null);
153: viaHeaders.addElement(viaHeader);
154: } catch (ParseException ex) {
155: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
156: Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
157: "RefreshTask.run(): can't create Via header: "
158: + ex);
159: }
160: } catch (IOException ioe) {
161: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
162: Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
163: "RefreshTask.run(): can't create Via header: "
164: + ioe);
165: }
166: }
167:
168: try {
169: clonedRequest.setVia(viaHeaders);
170: } catch (SipException ex) {
171: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
172: Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
173: "RefreshTask.run(): can't set Via header: "
174: + ex);
175: }
176: }
177: }
178:
179: /**
180: * Return the callback interface listening for events on this task
181: * @return the callback interface listening for events on this task
182: */
183: public SipRefreshListener getSipRefreshListener() {
184: return sipRefreshListener;
185: }
186:
187: /**
188: * Return the callback interface listening for events on this task
189: * @return the callback interface listening for events on this task
190: */
191: public SipConnectionNotifier getSipConnectionNotifier() {
192: return sipConnectionNotifier;
193: }
194:
195: /**
196: * Return the sipClientconnection on which is enabled the listener
197: * @return the sipClientconnection on which is enabled the listener
198: */
199: public SipClientConnection getSipClientConnection() {
200: return sipClientConnection;
201: }
202:
203: /**
204: * Updates the request in the sipClientConnection and sends it.
205: * @param updatedRequest the updated request
206: * @throws IOException if the message could not be sent or because
207: * of network failure
208: * @throws InterruptedIOException if a timeout occurs while
209: * either trying to send the message or if this Connection object
210: * is closed during this send operation
211: * @throws SipException INVALID_STATE if the message cannot be sent
212: * in this state. <br> INVALID_MESSAGE there was an error
213: * in message format
214: */
215: public synchronized void updateAndSendRequest(Request updatedRequest)
216: throws IOException, InterruptedIOException, SipException {
217: request = updatedRequest;
218: setRequestHeaders(request);
219: ((SipClientConnectionImpl) sipClientConnection)
220: .updateAndSendRequestFromRefresh(request);
221: }
222:
223: /**
224: * Updates the request in the sipClientConnection and calls
225: * SipClientConnection.openContentOutputStream() to fill
226: * the new message body content.
227: * @param updatedRequest the updated request
228: * @return OutputStream to write body content
229: * @throws IOException if the OutputStream can not be opened,
230: * because of an I/O error occurred.
231: * @throws SipException INVALID_STATE the OutputStream can not be opened
232: * in this state (e.g. no message initialized).
233: * UNKNOWN_LENGTH Content-Length header not set.
234: * UNKNOWN_TYPE Content-Type header not set.
235: */
236: public synchronized OutputStream updateRequestAndOpenOutputStream(
237: Request updatedRequest) throws IOException, SipException {
238:
239: request = updatedRequest;
240: setRequestHeaders(request);
241: return ((SipClientConnectionImpl) sipClientConnection)
242: .updateRequestAndOpenOutputStream(request);
243: }
244:
245: /**
246: * Gets the new caller identifier.
247: * @return the caller identifier
248: */
249: public CallIdHeader getNewCallId() {
250: return ((SipConnectionNotifierImpl) sipConnectionNotifier)
251: .getSipProvider().getNewCallId();
252: }
253:
254: /**
255: * Returns the request to refresh
256: * @return the request to refresh
257: */
258: public synchronized Request getRequest() {
259: return request;
260: }
261:
262: /**
263: * Returns the task identifier
264: * @return the task identifier
265: */
266: public String getTaskId() {
267: return taskId;
268: }
269: }
|