Skip to content

Commit 1452b5c

Browse files
committed
Support background loading of raw input streams
- Fixed generics (mix up of two ImageLoader types) - Removed unused code for handling headers, methods, request parameters - Use long for progress as streams max exceed 2 GB - Improved documentation of Image regarding background loading
1 parent 1dda20b commit 1452b5c

File tree

11 files changed

+232
-124
lines changed

11 files changed

+232
-124
lines changed

modules/javafx.graphics/src/main/java/com/sun/javafx/runtime/async/AbstractAsyncOperation.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ public abstract class AbstractAsyncOperation<V> implements AsyncOperation,
4646
Callable<V> {
4747

4848
protected final FutureTask<V> future;
49-
protected final AsyncOperationListener listener;
49+
protected final AsyncOperationListener<V> listener;
5050

51-
private int progressGranularity = 100;
52-
private int progressMax, lastProgress, progressIncrement, nextProgress, bytesRead;
51+
private long progressGranularity = 100;
52+
private long progressMax, lastProgress, progressIncrement, nextProgress, bytesRead;
5353

5454
protected AbstractAsyncOperation(final AsyncOperationListener<V> listener) {
5555
this.listener = listener;
@@ -109,8 +109,8 @@ public void start() {
109109
}
110110

111111
protected void notifyProgress() {
112-
final int last = lastProgress;
113-
final int max = progressMax;
112+
final long last = lastProgress;
113+
final long max = progressMax;
114114
Platform.runLater(() -> listener.onProgress(last, max));
115115
}
116116

@@ -123,11 +123,11 @@ protected void addProgress(int amount) {
123123
}
124124
}
125125

126-
protected int getProgressMax() {
126+
protected long getProgressMax() {
127127
return progressMax;
128128
}
129129

130-
protected void setProgressMax(int progressMax) {
130+
protected void setProgressMax(long progressMax) {
131131
if (progressMax == 0) {
132132
progressIncrement = progressGranularity;
133133
}
@@ -145,11 +145,11 @@ else if (progressMax == -1) {
145145
notifyProgress();
146146
}
147147

148-
protected int getProgressGranularity() {
148+
protected long getProgressGranularity() {
149149
return progressGranularity;
150150
}
151151

152-
protected void setProgressGranularity(int progressGranularity) {
152+
protected void setProgressGranularity(long progressGranularity) {
153153
this.progressGranularity = progressGranularity;
154154
progressIncrement = progressMax / progressGranularity;
155155
nextProgress = ((lastProgress / progressIncrement) + 1) * progressIncrement;

modules/javafx.graphics/src/main/java/com/sun/javafx/runtime/async/AbstractRemoteResource.java

Lines changed: 22 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,7 @@
2929
import java.io.IOException;
3030
import java.io.InputStream;
3131
import java.io.InterruptedIOException;
32-
import java.io.OutputStream;
33-
import java.net.HttpURLConnection;
34-
import java.net.URL;
35-
import java.net.URLConnection;
36-
import java.util.HashMap;
37-
import java.util.Iterator;
38-
import java.util.List;
39-
import java.util.Map;
32+
import java.util.Objects;
4033

4134
/**
4235
* Abstract base class for representing remote resources identified by a URL. Subclasses may plug in arbitrary
@@ -46,72 +39,39 @@
4639
*/
4740
public abstract class AbstractRemoteResource<T> extends AbstractAsyncOperation<T> {
4841

49-
protected final String url;
50-
protected final String method;
51-
protected final String outboundContent;
52-
protected int fileSize;
53-
private Map<String, String> headers = new HashMap<>();
54-
private Map<String, List<String>> responseHeaders = new HashMap<>();
55-
56-
protected AbstractRemoteResource(String url, AsyncOperationListener<T> listener) {
57-
this(url, "GET", listener);
42+
/**
43+
* @param stream an {@link InputStream}, cannot be {@code null}
44+
* @param size the size of the stream, or -1 if unknown
45+
*/
46+
public record SizedStream(InputStream stream, long size) {}
47+
48+
/**
49+
* An interface to provide a stream with a known (or unknown) size that
50+
* allows {@link IOException} to be thrown.
51+
*/
52+
public interface SizedStreamSupplier {
53+
SizedStream get() throws IOException;
5854
}
5955

60-
protected AbstractRemoteResource(String url, String method, AsyncOperationListener<T> listener) {
61-
this(url, method, null, listener);
62-
}
56+
private final SizedStreamSupplier sizedStreamSupplier;
6357

64-
protected AbstractRemoteResource(String url, String method, String outboundContent, AsyncOperationListener<T> listener) {
58+
protected AbstractRemoteResource(SizedStreamSupplier sizedStreamSupplier, AsyncOperationListener<T> listener) {
6559
super(listener);
66-
this.url = url;
67-
this.method = method;
68-
this.outboundContent = outboundContent;
60+
61+
this.sizedStreamSupplier = Objects.requireNonNull(sizedStreamSupplier, "sizedStreamSupplier");
6962
}
7063

71-
protected abstract T processStream(InputStream stream) throws IOException;
64+
protected abstract T processStream(InputStream stream);
7265

7366
@Override
7467
public T call() throws IOException {
75-
URL u = new URL(url);
76-
InputStream stream = null;
77-
final String protocol = u.getProtocol();
78-
if(protocol.equals("http") || protocol.equals("https")) {
79-
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
80-
conn.setRequestMethod(method);
81-
conn.setDoInput(true);
82-
83-
for (Map.Entry<String,String> entry : headers.entrySet()) {
84-
String key = entry.getKey();
85-
String value = entry.getValue();
86-
if (value != null && !value.equals(""))
87-
conn.setRequestProperty(key, value);
88-
}
89-
if(outboundContent != null && method.equals("POST")) {
90-
conn.setDoOutput(true);
91-
byte[] outBytes = outboundContent.getBytes("utf-8");
92-
conn.setRequestProperty("Content-Length", String.valueOf(outBytes.length));
93-
OutputStream out = conn.getOutputStream();
94-
out.write(outBytes);
95-
out.close();
96-
}
97-
conn.connect();
98-
fileSize = conn.getContentLength();
99-
setProgressMax(fileSize);
100-
responseHeaders = conn.getHeaderFields();
101-
102-
stream = new ProgressInputStream(conn.getInputStream());
103-
} else { // protocol is something other than http...
104-
URLConnection con = u.openConnection();
105-
setProgressMax(con.getContentLength());
106-
stream = new ProgressInputStream(con.getInputStream());
107-
}
68+
SizedStream sizedStream = sizedStreamSupplier.get();
69+
70+
setProgressMax(sizedStream.size);
10871

109-
try {
72+
try (ProgressInputStream stream = new ProgressInputStream(sizedStream.stream)) {
11073
return processStream(stream);
11174
}
112-
finally {
113-
stream.close();
114-
}
11575
}
11676

11777
protected class ProgressInputStream extends BufferedInputStream {
@@ -146,26 +106,4 @@ public int read(byte b[]) throws IOException {
146106
return bytes;
147107
}
148108
}
149-
150-
public void setHeader(String header, String value) {
151-
headers.put(header, value);
152-
}
153-
154-
public String getResponseHeader(String header) {
155-
String value = null;
156-
List<String> list = responseHeaders.get(header);
157-
// return a csv of the strings.
158-
if(list != null) {
159-
StringBuilder sb = new StringBuilder();
160-
Iterator iter = list.iterator();
161-
while(iter.hasNext()) {
162-
sb.append(iter.next());
163-
if(iter.hasNext()) {
164-
sb.append(',');
165-
}
166-
}
167-
value = sb.toString();
168-
}
169-
return value;
170-
}
171109
}

modules/javafx.graphics/src/main/java/com/sun/javafx/runtime/async/AsyncOperationListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*
3131
*/
3232
public interface AsyncOperationListener<V> {
33-
public void onProgress(int progressValue, int progressMax);
33+
public void onProgress(long progressValue, long progressMax);
3434
public void onCompletion(V value);
3535
public void onCancel();
3636
public void onException(Exception e);

modules/javafx.graphics/src/main/java/com/sun/javafx/tk/DummyToolkit.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,12 @@ public ImageLoader loadImage(InputStream stream, double width, double height, bo
131131
}
132132

133133
@Override
134-
public AsyncOperation loadImageAsync(AsyncOperationListener<? extends ImageLoader> listener, String url, double width, double height, boolean preserveRatio, boolean smooth) {
134+
public AsyncOperation loadImageAsync(AsyncOperationListener<ImageLoader> listener, String url, double width, double height, boolean preserveRatio, boolean smooth) {
135+
throw new UnsupportedOperationException("Not supported yet.");
136+
}
137+
138+
@Override
139+
public AsyncOperation loadImageAsync(AsyncOperationListener<ImageLoader> listener, InputStream stream, double width, double height, boolean preserveRatio, boolean smooth) {
135140
throw new UnsupportedOperationException("Not supported yet.");
136141
}
137142

modules/javafx.graphics/src/main/java/com/sun/javafx/tk/Toolkit.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,17 @@ public abstract ImageLoader loadImage(InputStream stream,
519519
boolean preserveRatio,
520520
boolean smooth);
521521
public abstract AsyncOperation loadImageAsync(
522-
AsyncOperationListener<? extends ImageLoader> listener,
522+
AsyncOperationListener<ImageLoader> listener,
523523
String url,
524524
double width, double height,
525525
boolean preserveRatio,
526526
boolean smooth);
527-
527+
public abstract AsyncOperation loadImageAsync(
528+
AsyncOperationListener<ImageLoader> listener,
529+
InputStream stream,
530+
double width, double height,
531+
boolean preserveRatio,
532+
boolean smooth);
528533
/*
529534
* The loadPlatformImage method supports the following image types:
530535
* - an object returned by the renderToImage method

modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/PrismImageLoader2.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
package com.sun.javafx.tk.quantum;
2727

28-
import java.io.IOException;
2928
import java.io.InputStream;
3029

3130
import com.sun.javafx.iio.ImageFrame;
@@ -227,7 +226,7 @@ public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) {
227226
}
228227

229228
static final class AsyncImageLoader
230-
extends AbstractRemoteResource<PrismImageLoader2>
229+
extends AbstractRemoteResource<com.sun.javafx.tk.ImageLoader>
231230
{
232231
private static final ExecutorService BG_LOADING_EXECUTOR =
233232
createExecutor();
@@ -237,27 +236,22 @@ static final class AsyncImageLoader
237236
boolean smooth;
238237

239238
public AsyncImageLoader(
240-
AsyncOperationListener<PrismImageLoader2> listener,
241-
String url,
239+
AsyncOperationListener<com.sun.javafx.tk.ImageLoader> listener,
240+
SizedStreamSupplier sizedStreamSupplier,
242241
double width, double height, boolean preserveRatio, boolean smooth)
243242
{
244-
super(url, listener);
243+
super(sizedStreamSupplier, listener);
245244
this.width = width;
246245
this.height = height;
247246
this.preserveRatio = preserveRatio;
248247
this.smooth = smooth;
249248
}
250249

251250
@Override
252-
protected PrismImageLoader2 processStream(InputStream stream) throws IOException {
251+
protected PrismImageLoader2 processStream(InputStream stream) {
253252
return new PrismImageLoader2(stream, width, height, preserveRatio, smooth);
254253
}
255254

256-
@Override
257-
public PrismImageLoader2 call() throws IOException {
258-
return AsyncImageLoader.super.call();
259-
}
260-
261255
@Override
262256
public void start() {
263257
BG_LOADING_EXECUTOR.execute(future);

modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
import javafx.stage.Window;
5858
import java.io.File;
5959
import java.io.InputStream;
60+
import java.net.HttpURLConnection;
61+
import java.net.URL;
62+
import java.net.URLConnection;
6063
import java.nio.Buffer;
6164
import java.nio.ByteBuffer;
6265
import java.nio.IntBuffer;
@@ -92,6 +95,8 @@
9295
import com.sun.javafx.perf.PerformanceTracker;
9396
import com.sun.javafx.runtime.async.AbstractRemoteResource;
9497
import com.sun.javafx.runtime.async.AsyncOperationListener;
98+
import com.sun.javafx.runtime.async.AbstractRemoteResource.SizedStream;
99+
import com.sun.javafx.runtime.async.AbstractRemoteResource.SizedStreamSupplier;
95100
import com.sun.javafx.scene.text.TextLayoutFactory;
96101
import com.sun.javafx.sg.prism.NGNode;
97102
import com.sun.javafx.tk.CompletionListener;
@@ -813,10 +818,42 @@ private float getMaxRenderScale() {
813818
return new PrismImageLoader2(stream, width, height, preserveRatio, smooth);
814819
}
815820

816-
@Override public AbstractRemoteResource<? extends ImageLoader> loadImageAsync(
817-
AsyncOperationListener listener, String url,
821+
@Override public AbstractRemoteResource<ImageLoader> loadImageAsync(
822+
AsyncOperationListener<ImageLoader> listener, String url,
818823
double width, double height, boolean preserveRatio, boolean smooth) {
819-
return new PrismImageLoader2.AsyncImageLoader(listener, url, width, height, preserveRatio, smooth);
824+
825+
SizedStreamSupplier sizedStreamSupplier = () -> {
826+
URL u = new URL(url);
827+
String protocol = u.getProtocol();
828+
829+
if(protocol.equals("http") || protocol.equals("https")) {
830+
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
831+
832+
conn.setRequestMethod("GET");
833+
conn.connect();
834+
835+
long size = conn.getContentLengthLong();
836+
837+
return new SizedStream(conn.getInputStream(), size);
838+
}
839+
840+
// protocol is something other than http...
841+
URLConnection conn = u.openConnection();
842+
long size = conn.getContentLengthLong();
843+
844+
return new SizedStream(conn.getInputStream(), size);
845+
};
846+
847+
return new PrismImageLoader2.AsyncImageLoader(listener, sizedStreamSupplier, width, height, preserveRatio, smooth);
848+
}
849+
850+
@Override public AbstractRemoteResource<ImageLoader> loadImageAsync(
851+
AsyncOperationListener<ImageLoader> listener, InputStream stream,
852+
double width, double height, boolean preserveRatio, boolean smooth) {
853+
854+
SizedStreamSupplier sizedStreamSupplier = () -> new SizedStream(stream, -1);
855+
856+
return new PrismImageLoader2.AsyncImageLoader(listener, sizedStreamSupplier, width, height, preserveRatio, smooth);
820857
}
821858

822859
// Note that this method should only be called by PlatformImpl.runLater

0 commit comments

Comments
 (0)