Browse Source

Merge pull request #22 from greboid/tidying

Tidy downloader.
pull/24/head
Chris Smith 9 years ago
parent
commit
d84337a9ca

+ 50
- 0
src/com/dmdirc/util/collections/CollectionFunctions.java View File

1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.util.collections;
24
+
25
+import java.io.UnsupportedEncodingException;
26
+import java.net.URLEncoder;
27
+import java.util.Map;
28
+import java.util.stream.Stream;
29
+
30
+/**
31
+ * Collection related functions.
32
+ */
33
+public final class CollectionFunctions {
34
+
35
+    private CollectionFunctions() {
36
+    }
37
+
38
+    public static Stream<String> flattenAndEncodeKeyPair(final Map.Entry<String, String> entry) {
39
+        String key;
40
+        String value;
41
+        try {
42
+            key = URLEncoder.encode(entry.getKey(), "UTF-8");
43
+            value = URLEncoder.encode(entry.getValue(), "UTF-8");
44
+        } catch (UnsupportedEncodingException ex){
45
+            key = entry.getKey();
46
+            value = entry.getValue();
47
+        }
48
+        return Stream.of(key + '=' + value);
49
+    }
50
+}

+ 15
- 63
src/com/dmdirc/util/io/Downloader.java View File

22
 
22
 
23
 package com.dmdirc.util.io;
23
 package com.dmdirc.util.io;
24
 
24
 
25
+import com.dmdirc.util.collections.CollectionFunctions;
26
+
25
 import java.io.BufferedReader;
27
 import java.io.BufferedReader;
26
 import java.io.DataOutputStream;
28
 import java.io.DataOutputStream;
27
 import java.io.IOException;
29
 import java.io.IOException;
28
-import java.io.InputStream;
29
 import java.io.InputStreamReader;
30
 import java.io.InputStreamReader;
30
-import java.io.OutputStream;
31
 import java.net.URL;
31
 import java.net.URL;
32
 import java.net.URLConnection;
32
 import java.net.URLConnection;
33
-import java.net.URLEncoder;
34
 import java.nio.file.Files;
33
 import java.nio.file.Files;
35
 import java.nio.file.Path;
34
 import java.nio.file.Path;
36
-import java.util.ArrayList;
37
 import java.util.List;
35
 import java.util.List;
38
 import java.util.Map;
36
 import java.util.Map;
37
+import java.util.stream.Collectors;
39
 
38
 
40
 /**
39
 /**
41
  * Allows easy downloading of files from HTTP sites.
40
  * Allows easy downloading of files from HTTP sites.
50
      * @throws IOException If there's an I/O error while downloading
49
      * @throws IOException If there's an I/O error while downloading
51
      */
50
      */
52
     public List<String> getPage(final String url) throws IOException {
51
     public List<String> getPage(final String url) throws IOException {
53
-
54
         return getPage(url, "");
52
         return getPage(url, "");
55
     }
53
     }
56
 
54
 
64
      */
62
      */
65
     public List<String> getPage(final String url, final String postData)
63
     public List<String> getPage(final String url, final String postData)
66
             throws IOException {
64
             throws IOException {
67
-
68
-        final List<String> res = new ArrayList<>();
69
-
70
         final URLConnection urlConn = getConnection(url, postData);
65
         final URLConnection urlConn = getConnection(url, postData);
71
-
66
+        final List<String> res;
72
         try (BufferedReader in = new BufferedReader(new InputStreamReader(
67
         try (BufferedReader in = new BufferedReader(new InputStreamReader(
73
                 urlConn.getInputStream()))) {
68
                 urlConn.getInputStream()))) {
74
-            String line;
75
-            do {
76
-                line = in.readLine();
77
-
78
-                if (line != null) {
79
-                    res.add(line);
80
-                }
81
-            } while (line != null);
69
+            res = in.lines().collect(Collectors.toList());
82
         }
70
         }
83
-
84
         return res;
71
         return res;
85
     }
72
     }
86
 
73
 
94
      */
81
      */
95
     public List<String> getPage(final String url,
82
     public List<String> getPage(final String url,
96
             final Map<String, String> postData) throws IOException {
83
             final Map<String, String> postData) throws IOException {
97
-        final StringBuilder data = new StringBuilder();
98
-
99
-        for (Map.Entry<String, String> entry : postData.entrySet()) {
100
-            data.append('&');
101
-            data.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
102
-            data.append('=');
103
-            data.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
104
-        }
105
-
106
-        return getPage(url, data.length() == 0 ? "" : data.substring(1));
84
+        return getPage(url, postData.entrySet().stream()
85
+                .flatMap(CollectionFunctions::flattenAndEncodeKeyPair)
86
+                .collect(Collectors.joining("&")));
107
     }
87
     }
108
 
88
 
109
     /**
89
     /**
126
      * @param listener The progress listener for this download
106
      * @param listener The progress listener for this download
127
      * @throws IOException If there's an I/O error while downloading
107
      * @throws IOException If there's an I/O error while downloading
128
      */
108
      */
129
-    public void downloadPage(final String url, final Path file,
130
-            final DownloadListener listener) throws IOException {
131
-
132
-        final URLConnection urlConn = getConnection(url, "");
133
-
134
-        try (OutputStream output = Files.newOutputStream(file);
135
-                InputStream input = urlConn.getInputStream()) {
136
-            final int length = urlConn.getContentLength();
137
-
138
-            if (listener != null) {
139
-                listener.setIndeterminate(length == -1);
140
-            }
141
-
142
-            final byte[] buffer = new byte[512];
143
-            int count;
144
-
145
-            int current = 0;
146
-            do {
147
-                count = input.read(buffer);
148
-
149
-                if (count > 0) {
150
-                    current += count;
151
-                    output.write(buffer, 0, count);
152
-
153
-                    if (listener != null && length != -1) {
154
-                        listener.downloadProgress(100 * (float) current
155
-                                / length);
156
-                    }
157
-                }
158
-            } while (count > 0);
159
-        }
109
+    public void downloadPage(final String url, final Path file, final DownloadListener listener)
110
+            throws IOException {
111
+        final URLConnection connection = getConnection(url, "");
112
+        Files.copy(new ListenerInputStream(connection.getInputStream(), listener,
113
+                        connection.getContentLength()), file);
160
     }
114
     }
161
 
115
 
162
     /**
116
     /**
167
      * @return An URLConnection for the specified URL/data
121
      * @return An URLConnection for the specified URL/data
168
      * @throws IOException If an I/O exception occurs while connecting
122
      * @throws IOException If an I/O exception occurs while connecting
169
      */
123
      */
170
-    private URLConnection getConnection(final String url,
171
-            final String postData)
124
+    private URLConnection getConnection(final String url, final String postData)
172
             throws IOException {
125
             throws IOException {
173
         final URLConnection urlConn = getURLConnection(url);
126
         final URLConnection urlConn = getURLConnection(url);
174
 
127
 
178
         urlConn.setConnectTimeout(10000);
131
         urlConn.setConnectTimeout(10000);
179
 
132
 
180
         if (!postData.isEmpty()) {
133
         if (!postData.isEmpty()) {
181
-            urlConn.setRequestProperty("Content-Type",
182
-                    "application/x-www-form-urlencoded");
134
+            urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
183
 
135
 
184
             try (DataOutputStream out = new DataOutputStream(urlConn.getOutputStream())) {
136
             try (DataOutputStream out = new DataOutputStream(urlConn.getOutputStream())) {
185
                 out.writeBytes(postData);
137
                 out.writeBytes(postData);

+ 128
- 0
src/com/dmdirc/util/io/ListenerInputStream.java View File

1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.util.io;
24
+
25
+import java.io.FilterInputStream;
26
+import java.io.IOException;
27
+import java.io.InputStream;
28
+
29
+import javax.annotation.Nonnull;
30
+
31
+/**
32
+ * Wrapped {@link InputStream} that provides updates to a {@link DownloadListener} as it reads a
33
+ * stream.
34
+ */
35
+public class ListenerInputStream extends FilterInputStream {
36
+
37
+    private final DownloadListener listener;
38
+    private final int length;
39
+    private int count;
40
+    private int mark;
41
+
42
+    /**
43
+     * Creates a new stream.
44
+     *
45
+     * @param in        Stream to wrap
46
+     * @param listener  Listener to gives up dates to
47
+     * @param length    Length of the stream, if -1 the listener will be indeterminate
48
+     */
49
+    public ListenerInputStream(@Nonnull final InputStream in, final DownloadListener listener,
50
+            final int length) {
51
+        super(in);
52
+        this.listener = listener;
53
+        this.length = length;
54
+        count = 0;
55
+        mark = count;
56
+        if (listener != null) {
57
+            listener.setIndeterminate(length == -1);
58
+        }
59
+    }
60
+
61
+    @Override
62
+    public int read() throws IOException {
63
+        final int read = super.read();
64
+        return update(read);
65
+    }
66
+
67
+    @Override
68
+    public int read(@Nonnull final byte[] b) throws IOException {
69
+        final int read = super.read(b);
70
+        return update(read);
71
+    }
72
+
73
+    @Override
74
+    public int read(@Nonnull final byte[] b, final int off, final int len) throws IOException {
75
+        final int read = super.read(b, off, len);
76
+        return update(read);
77
+    }
78
+
79
+    @Override
80
+    public long skip(final long n) throws IOException {
81
+        final long read = super.skip(n);
82
+        return update((int) read);
83
+    }
84
+
85
+    @Override
86
+    public int available() throws IOException {
87
+        return super.available();
88
+    }
89
+
90
+    @Override
91
+    public void close() throws IOException {
92
+        super.close();
93
+    }
94
+
95
+    @Override
96
+    public synchronized void mark(final int readlimit) {
97
+        mark = count;
98
+        super.mark(readlimit);
99
+    }
100
+
101
+    @Override
102
+    public synchronized void reset() throws IOException {
103
+        update(mark - count);
104
+        super.reset();
105
+    }
106
+
107
+    @Override
108
+    public boolean markSupported() {
109
+        return super.markSupported();
110
+    }
111
+
112
+    /**
113
+     * Updates the listener and total read count.
114
+     *
115
+     * @param read Number of bytes further into stream.
116
+     *
117
+     * @return Returns the number of bytes read.
118
+     */
119
+    private int update(final int read) {
120
+        if (read > 0) {
121
+            count += read;
122
+            if (listener != null && length != -1) {
123
+                listener.downloadProgress(100 * (float) count / length);
124
+            }
125
+        }
126
+        return read;
127
+    }
128
+}

+ 50
- 0
test/com/dmdirc/util/collections/CollectionFunctionsTest.java View File

1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.util.collections;
24
+
25
+import com.google.common.collect.ImmutableMap;
26
+
27
+import java.util.List;
28
+import java.util.Map;
29
+import java.util.stream.Collectors;
30
+
31
+import org.junit.Test;
32
+
33
+import static junit.framework.TestCase.assertEquals;
34
+
35
+public class CollectionFunctionsTest {
36
+
37
+    @Test
38
+    public void testflattenAndEncodeKeyPair() throws Exception {
39
+        final Map<String, String> map = ImmutableMap.<String, String>builder()
40
+                .put("key", "value")
41
+                .put("key&", "value&")
42
+                .build();
43
+        final List<String> result = map.entrySet().stream()
44
+                .flatMap(CollectionFunctions::flattenAndEncodeKeyPair)
45
+                .collect(Collectors.toList());
46
+        assertEquals(2, result.size());
47
+        assertEquals("key=value", result.get(0));
48
+        assertEquals("key%26=value%26", result.get(1));
49
+    }
50
+}

+ 14
- 0
test/com/dmdirc/util/io/DownloaderTest.java View File

104
         assertTrue(postDataString1.equals(os.toString()) || postDataString2.equals(os.toString()));
104
         assertTrue(postDataString1.equals(os.toString()) || postDataString2.equals(os.toString()));
105
     }
105
     }
106
 
106
 
107
+    @Test
108
+    public void testGetPageMapEncoding() throws IOException {
109
+        final Map<String, String> postData = Maps.newHashMap();
110
+        postData.put("ke&y1", "value1");
111
+        postData.put("key2", "val&ue2");
112
+        new TestableDownloader().getPage("rar", postData);
113
+        verify(mockedConnection).setRequestProperty("Content-Type",
114
+                "application/x-www-form-urlencoded");
115
+
116
+        final String postDataString1 = "ke%26y1=value1&key2=val%26ue2";
117
+        final String postDataString2 = "key2=val%26ue2&ke%26y1=value1";
118
+        assertTrue(postDataString1.equals(os.toString()) || postDataString2.equals(os.toString()));
119
+    }
120
+
107
     @Test
121
     @Test
108
     public void testDownloadPage() throws IOException {
122
     public void testDownloadPage() throws IOException {
109
         final Path file = fakeFS.getPath("test.txt");
123
         final Path file = fakeFS.getPath("test.txt");

Loading…
Cancel
Save