KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > core > streams > PollingOutputStream


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.internal.core.streams;
12
13 import java.io.FilterOutputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.InterruptedIOException JavaDoc;
16 import java.io.OutputStream JavaDoc;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.OperationCanceledException;
20 import org.eclipse.team.internal.core.Messages;
21 import org.eclipse.team.internal.core.Policy;
22
23 /**
24  * Polls a progress monitor periodically and handles timeouts over extended durations.
25  * For this class to be effective, a high numAttempts should be specified, and the
26  * underlying stream should time out frequently on writes (every second or so).
27  *
28  * Supports resuming partially completed operations after an InterruptedIOException
29  * if the underlying stream does. Check the bytesTransferred field to determine how
30  * much of the operation completed; conversely, at what point to resume.
31  */

32 public class PollingOutputStream extends FilterOutputStream JavaDoc {
33     private static final boolean DEBUG = Policy.DEBUG_STREAMS;
34     private int numAttempts;
35     private IProgressMonitor monitor;
36     private boolean cancellable;
37     
38     /**
39      * Creates a new polling output stream.
40      * @param out the underlying output stream
41      * @param numAttempts the number of attempts before issuing an InterruptedIOException,
42      * if 0, retries indefinitely until canceled
43      * @param monitor the progress monitor to be polled for cancellation
44      */

45     public PollingOutputStream(OutputStream JavaDoc out, int numAttempts, IProgressMonitor monitor) {
46         super(out);
47         this.numAttempts = numAttempts;
48         this.monitor = monitor;
49         this.cancellable = true;
50     }
51     
52     /**
53      * Wraps the underlying stream's method.
54      * @throws OperationCanceledException if the progress monitor is canceled
55      * @throws InterruptedIOException if the underlying operation times out numAttempts times
56      * and no data was sent, bytesTransferred will be zero
57      * @throws IOException if an i/o error occurs
58      */

59     public void write(int b) throws IOException JavaDoc {
60         int attempts = 0;
61         for (;;) {
62             if (checkCancellation()) throw new OperationCanceledException();
63             try {
64                 out.write(b);
65                 return;
66             } catch (InterruptedIOException JavaDoc e) {
67                 if (++attempts == numAttempts)
68                     throw new InterruptedIOException JavaDoc(Messages.PollingOutputStream_writeTimeout);
69                 if (DEBUG) System.out.println("write retry=" + attempts); //$NON-NLS-1$
70
}
71         }
72     }
73     
74     /**
75      * Wraps the underlying stream's method.
76      * @throws OperationCanceledException if the progress monitor is canceled
77      * @throws InterruptedIOException if the underlying operation times out numAttempts times,
78      * bytesTransferred will reflect the number of bytes sent
79      * @throws IOException if an i/o error occurs
80      */

81     public void write(byte[] buffer, int off, int len) throws IOException JavaDoc {
82         int count = 0;
83         int attempts = 0;
84         for (;;) {
85             if (checkCancellation()) throw new OperationCanceledException();
86             try {
87                 out.write(buffer, off, len);
88                 return;
89             } catch (InterruptedIOException JavaDoc e) {
90                 int amount = e.bytesTransferred;
91                 if (amount != 0) { // keep partial transfer
92
len -= amount;
93                     if (len <= 0) return;
94                     off += amount;
95                     count += amount;
96                     attempts = 0; // made some progress, don't time out quite yet
97
}
98                 if (++attempts == numAttempts) {
99                     e = new InterruptedIOException JavaDoc(Messages.PollingOutputStream_writeTimeout);
100                     e.bytesTransferred = count;
101                     throw e;
102                 }
103                 if (DEBUG) System.out.println("write retry=" + attempts); //$NON-NLS-1$
104
}
105         }
106     }
107
108     /**
109      * Wraps the underlying stream's method.
110      * @throws OperationCanceledException if the progress monitor is canceled
111      * @throws InterruptedIOException if the underlying operation times out numAttempts times,
112      * bytesTransferred will reflect the number of bytes sent
113      * @throws IOException if an i/o error occurs
114      */

115     public void flush() throws IOException JavaDoc {
116         int count = 0;
117         int attempts = 0;
118         for (;;) {
119             if (checkCancellation()) throw new OperationCanceledException();
120             try {
121                 out.flush();
122                 return;
123             } catch (InterruptedIOException JavaDoc e) {
124                 int amount = e.bytesTransferred;
125                 if (amount != 0) { // keep partial transfer
126
count += amount;
127                     attempts = 0; // made some progress, don't time out quite yet
128
}
129                 if (++attempts == numAttempts) {
130                     e = new InterruptedIOException JavaDoc(Messages.PollingOutputStream_writeTimeout);
131                     e.bytesTransferred = count;
132                     throw e;
133                 }
134                 if (DEBUG) System.out.println("write retry=" + attempts); //$NON-NLS-1$
135
}
136         }
137     }
138     
139     /**
140      * Calls flush() then close() on the underlying stream.
141      * @throws OperationCanceledException if the progress monitor is canceled
142      * @throws InterruptedIOException if the underlying operation times out numAttempts times,
143      * bytesTransferred will reflect the number of bytes sent during the flush()
144      * @throws IOException if an i/o error occurs
145      */

146     public void close() throws IOException JavaDoc {
147         int attempts = numAttempts - 1; // fail fast if flush() does times out
148
try {
149             out.flush();
150             attempts = 0;
151         } finally {
152             boolean stop = false;
153             while (!stop) {
154                 try {
155                     out.close();
156                     stop = true;
157                 } catch (InterruptedIOException JavaDoc e) {
158                     if (checkCancellation()) throw new OperationCanceledException();
159                     if (++attempts == numAttempts)
160                         throw new InterruptedIOException JavaDoc(Messages.PollingOutputStream_closeTimeout);
161                     if (DEBUG) System.out.println("close retry=" + attempts); //$NON-NLS-1$
162
}
163             }
164         }
165     }
166     
167     /**
168      * Called to set whether cancellation will be checked by this stream. Turning cancellation checking
169      * off can be very useful for protecting critical portions of a protocol that shouldn't be interrupted.
170      * For example, it is often necessary to protect login sequences.
171      * @param cancellable a flag controlling whether this stream will check for cancellation.
172      */

173     public void setIsCancellable(boolean cancellable) {
174         this.cancellable = cancellable;
175     }
176
177     /**
178      * Checked whether the monitor for this stream has been cancelled. If the cancellable
179      * flag is <code>false</code> then the monitor is never cancelled.
180      * @return <code>true</code> if the monitor has been cancelled and <code>false</code>
181      * otherwise.
182      */

183     private boolean checkCancellation() {
184         if(cancellable) {
185             return monitor.isCanceled();
186         } else {
187             return false;
188         }
189     }
190 }
191
Popular Tags