1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client.util;
20
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.nio.channels.SeekableByteChannel;
25 import java.nio.file.AccessDeniedException;
26 import java.nio.file.Files;
27 import java.nio.file.NoSuchFileException;
28 import java.nio.file.Path;
29 import java.nio.file.StandardOpenOption;
30 import java.util.Iterator;
31 import java.util.NoSuchElementException;
32
33 import org.eclipse.jetty.client.api.ContentProvider;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
36
37
38
39
40
41
42
43 public class PathContentProvider implements ContentProvider
44 {
45 private static final Logger LOG = Log.getLogger(PathContentProvider.class);
46
47 private final Path filePath;
48 private final long fileSize;
49 private final int bufferSize;
50
51 public PathContentProvider(Path filePath) throws IOException
52 {
53 this(filePath, 4096);
54 }
55
56 public PathContentProvider(Path filePath, int bufferSize) throws IOException
57 {
58 if (!Files.isRegularFile(filePath))
59 throw new NoSuchFileException(filePath.toString());
60 if (!Files.isReadable(filePath))
61 throw new AccessDeniedException(filePath.toString());
62 this.filePath = filePath;
63 this.fileSize = Files.size(filePath);
64 this.bufferSize = bufferSize;
65 }
66
67 @Override
68 public long getLength()
69 {
70 return fileSize;
71 }
72
73 @Override
74 public Iterator<ByteBuffer> iterator()
75 {
76 return new PathIterator();
77 }
78
79 private class PathIterator implements Iterator<ByteBuffer>, Closeable
80 {
81 private final ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
82 private SeekableByteChannel channel;
83 private long position;
84
85 @Override
86 public boolean hasNext()
87 {
88 return position < getLength();
89 }
90
91 @Override
92 public ByteBuffer next()
93 {
94 try
95 {
96 if (channel == null)
97 {
98 channel = Files.newByteChannel(filePath, StandardOpenOption.READ);
99 LOG.debug("Opened file {}", filePath);
100 }
101
102 buffer.clear();
103 int read = channel.read(buffer);
104 if (read < 0)
105 throw new NoSuchElementException();
106
107 if (LOG.isDebugEnabled())
108 LOG.debug("Read {} bytes from {}", read, filePath);
109
110 position += read;
111
112 if (!hasNext())
113 close();
114
115 buffer.flip();
116 return buffer;
117 }
118 catch (NoSuchElementException x)
119 {
120 close();
121 throw x;
122 }
123 catch (Exception x)
124 {
125 close();
126 throw (NoSuchElementException)new NoSuchElementException().initCause(x);
127 }
128 }
129
130 @Override
131 public void remove()
132 {
133 throw new UnsupportedOperationException();
134 }
135
136 @Override
137 public void close()
138 {
139 try
140 {
141 if (channel != null)
142 channel.close();
143 }
144 catch (Exception x)
145 {
146 LOG.ignore(x);
147 }
148 }
149 }
150 }