File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\model\LargeText.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.model;
25
26 import hudson.util.ByteBuffer;
27 import hudson.util.CharSpool;
28 import hudson.util.LineEndNormalizingWriter;
29 import org.kohsuke.stapler.StaplerRequest;
30 import org.kohsuke.stapler.StaplerResponse;
31 import org.kohsuke.stapler.framework.io.WriterOutputStream;
32 import org.apache.commons.io.output.CountingOutputStream;
33
34 import javax.servlet.http.HttpServletResponse;
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.io.RandomAccessFile;
40 import java.io.Writer;
41 import java.io.Reader;
42 import java.io.InputStreamReader;
43
44 /**
45 * Represents a large text data.
46 *
47 * <p>
48 * This class defines methods for handling progressive text update.
49 *
50 * @author Kohsuke Kawaguchi
51 * @deprecated moved to stapler, as of Hudson 1.220
52 */
53 public class LargeText {
54 /**
55 * Represents the data source of this text.
56 */
57 private interface Source {
58 Session open() throws IOException;
59 long length();
60 boolean exists();
61 }
62 private final Source source;
63
64 private volatile boolean completed;
65
66 public LargeText(final File file, boolean completed) {
67 this.source = new Source() {
68 public Session open() throws IOException {
69 return new FileSession(file);
70 }
71
72 public long length() {
73 return file.length();
74 }
75
76 public boolean exists() {
77 return file.exists();
78 }
79 };
80 this.completed = completed;
81 }
82
83 public LargeText(final ByteBuffer memory, boolean completed) {
84 this.source = new Source() {
85 public Session open() throws IOException {
86 return new BufferSession(memory);
87 }
88
89 public long length() {
90 return memory.length();
91 }
92
93 public boolean exists() {
94 return true;
95 }
96 };
97 this.completed = completed;
98 }
99
100 public void markAsComplete() {
101 completed = true;
102 }
103
104 public boolean isComplete() {
105 return completed;
106 }
107
108 /**
109 * Returns {@link Reader} for reading the raw bytes.
110 */
111 public Reader readAll() throws IOException {
112 return new InputStreamReader(new InputStream() {
113 final Session session = source.open();
114 public int read() throws IOException {
115 byte[] buf = new byte[1];
116 int n = session.read(buf);
117 if(n==1) return buf[0];
118 else return -1; // EOF
119 }
120
121 public int read(byte[] buf, int off, int len) throws IOException {
122 return session.read(buf,off,len);
123 }
124
125 public void close() throws IOException {
126 session.close();
127 }
128 });
129 }
130
131 /**
132 * Writes the tail portion of the file to the {@link Writer}.
133 *
134 * <p>
135 * The text file is assumed to be in the system default encoding.
136 *
137 * @param start
138 * The byte offset in the input file where the write operation starts.
139 *
140 * @return
141 * if the file is still being written, this method writes the file
142 * until the last newline character and returns the offset to start
143 * the next write operation.
144 */
145 public long writeLogTo(long start, Writer w) throws IOException {
146 CountingOutputStream os = new CountingOutputStream(new WriterOutputStream(w));
147
148 Session f = source.open();
149 f.skip(start);
150
151 if(completed) {
152 // write everything till EOF
153 byte[] buf = new byte[1024];
154 int sz;
155 while((sz=f.read(buf))>=0)
156 os.write(buf,0,sz);
157 } else {
158 ByteBuf buf = new ByteBuf(null,f);
159 HeadMark head = new HeadMark(buf);
160 TailMark tail = new TailMark(buf);
161
162 while(tail.moveToNextLine(f)) {
163 head.moveTo(tail,os);
164 }
165 head.finish(os);
166 }
167
168 f.close();
169 os.flush();
170
171 return os.getCount()+start;
172 }
173
174 /**
175 * Implements the progressive text handling.
176 * This method is used as a "web method" with progressiveText.jelly.
177 */
178 public void doProgressText(StaplerRequest req, StaplerResponse rsp) throws IOException {
179 rsp.setContentType("text/plain");
180 rsp.setStatus(HttpServletResponse.SC_OK);
181
182 if(!source.exists()) {
183 // file doesn't exist yet
184 rsp.addHeader("X-Text-Size","0");
185 rsp.addHeader("X-More-Data","true");
186 return;
187 }
188
189 long start = 0;
190 String s = req.getParameter("start");
191 if(s!=null)
192 start = Long.parseLong(s);
193
194 if(source.length() < start )
195 start = 0; // text rolled over
196
197 CharSpool spool = new CharSpool();
198 long r = writeLogTo(start,spool);
199
200 rsp.addHeader("X-Text-Size",String.valueOf(r));
201 if(!completed)
202 rsp.addHeader("X-More-Data","true");
203
204 // when sending big text, try compression. don't bother if it's small
205 Writer w;
206 if(r-start>4096)
207 w = rsp.getCompressedWriter(req);
208 else
209 w = rsp.getWriter();
210 spool.writeTo(new LineEndNormalizingWriter(w));
211 w.close();
212
213 }
214
215 /**
216 * Points to a byte in the buffer.
217 */
218 private static class Mark {
219 protected ByteBuf buf;
220 protected int pos;
221
222 public Mark(ByteBuf buf) {
223 this.buf = buf;
224 }
225 }
226
227 /**
228 * Points to the start of the region that's not committed
229 * to the output yet.
230 */
231 private static final class HeadMark extends Mark {
232 public HeadMark(ByteBuf buf) {
233 super(buf);
234 }
235
236 /**
237 * Moves this mark to 'that' mark, and writes the data
238 * to {@link OutputStream} if necessary.
239 */
240 void moveTo(Mark that, OutputStream os) throws IOException {
241 while(this.buf!=that.buf) {
242 os.write(buf.buf,0,buf.size);
243 buf = buf.next;
244 pos = 0;
245 }
246
247 this.pos = that.pos;
248 }
249
250 void finish(OutputStream os) throws IOException {
251 os.write(buf.buf,0,pos);
252 }
253 }
254
255 /**
256 * Points to the end of the region.
257 */
258 private static final class TailMark extends Mark {
259 public TailMark(ByteBuf buf) {
260 super(buf);
261 }
262
263 boolean moveToNextLine(Session f) throws IOException {
264 while(true) {
265 while(pos==buf.size) {
266 if(!buf.isFull()) {
267 // read until EOF
268 return false;
269 } else {
270 // read into the next buffer
271 buf = new ByteBuf(buf,f);
272 pos = 0;
273 }
274 }
275 byte b = buf.buf[pos++];
276 if(b=='\r' || b=='\n')
277 return true;
278 }
279 }
280 }
281
282 private static final class ByteBuf {
283 private final byte[] buf = new byte[1024];
284 private int size = 0;
285 private ByteBuf next;
286
287 public ByteBuf(ByteBuf previous, Session f) throws IOException {
288 if(previous!=null) {
289 assert previous.next==null;
290 previous.next = this;
291 }
292
293 while(!this.isFull()) {
294 int chunk = f.read(buf, size, buf.length - size);
295 if(chunk==-1)
296 return;
297 size+= chunk;
298 }
299 }
300
301 public boolean isFull() {
302 return buf.length==size;
303 }
304 }
305
306 /**
307 * Represents the read session of the {@link Source}.
308 * Methods generally follow the contracts of {@link InputStream}.
309 */
310 private interface Session {
311 void close() throws IOException;
312 void skip(long start) throws IOException;
313 int read(byte[] buf) throws IOException;
314 int read(byte[] buf, int offset, int length) throws IOException;
315 }
316
317 /**
318 * {@link Session} implementation over {@link RandomAccessFile}.
319 */
320 private static final class FileSession implements Session {
321 private final RandomAccessFile file;
322
323 public FileSession(File file) throws IOException {
324 this.file = new RandomAccessFile(file,"r");
325 }
326
327 public void close() throws IOException {
328 file.close();
329 }
330
331 public void skip(long start) throws IOException {
332 file.seek(file.getFilePointer()+start);
333 }
334
335 public int read(byte[] buf) throws IOException {
336 return file.read(buf);
337 }
338
339 public int read(byte[] buf, int offset, int length) throws IOException {
340 return file.read(buf,offset,length);
341 }
342 }
343
344 /**
345 * {@link Session} implementation over {@link ByteBuffer}.
346 */
347 private static final class BufferSession implements Session {
348 private final InputStream in;
349
350 public BufferSession(ByteBuffer buf) {
351 this.in = buf.newInputStream();
352 }
353
354
355 public void close() throws IOException {
356 in.close();
357 }
358
359 public void skip(long n) throws IOException {
360 while(n>0)
361 n -= in.skip(n);
362 }
363
364 public int read(byte[] buf) throws IOException {
365 return in.read(buf);
366 }
367
368 public int read(byte[] buf, int offset, int length) throws IOException {
369 return in.read(buf,offset,length);
370 }
371 }
372 }
373