-
Notifications
You must be signed in to change notification settings - Fork 534
8361286: Allow enabling of background loading for images loaded from an InputStream #1875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1452b5c
63e652e
cef710c
2e23626
65bc250
6494c52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,14 +29,7 @@ | |
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InterruptedIOException; | ||
import java.io.OutputStream; | ||
import java.net.HttpURLConnection; | ||
import java.net.URL; | ||
import java.net.URLConnection; | ||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
/** | ||
* Abstract base class for representing remote resources identified by a URL. Subclasses may plug in arbitrary | ||
|
@@ -46,72 +39,39 @@ | |
*/ | ||
public abstract class AbstractRemoteResource<T> extends AbstractAsyncOperation<T> { | ||
|
||
protected final String url; | ||
protected final String method; | ||
protected final String outboundContent; | ||
protected int fileSize; | ||
private Map<String, String> headers = new HashMap<>(); | ||
private Map<String, List<String>> responseHeaders = new HashMap<>(); | ||
|
||
protected AbstractRemoteResource(String url, AsyncOperationListener<T> listener) { | ||
this(url, "GET", listener); | ||
/** | ||
* @param stream an {@link InputStream}, cannot be {@code null} | ||
* @param size the size of the stream, or -1 if unknown | ||
*/ | ||
public record SizedStream(InputStream stream, long size) {} | ||
|
||
/** | ||
* An interface to provide a stream with a known (or unknown) size that | ||
* allows {@link IOException} to be thrown. | ||
*/ | ||
public interface SizedStreamSupplier { | ||
SizedStream get() throws IOException; | ||
} | ||
|
||
protected AbstractRemoteResource(String url, String method, AsyncOperationListener<T> listener) { | ||
this(url, method, null, listener); | ||
} | ||
private final SizedStreamSupplier sizedStreamSupplier; | ||
|
||
protected AbstractRemoteResource(String url, String method, String outboundContent, AsyncOperationListener<T> listener) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that outboundContent calls are no where used. Is this the reason we are cleaning up this code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I generally remove code that I see is unused, if it otherwise would have needed to be adjusted. |
||
protected AbstractRemoteResource(SizedStreamSupplier sizedStreamSupplier, AsyncOperationListener<T> listener) { | ||
super(listener); | ||
this.url = url; | ||
this.method = method; | ||
this.outboundContent = outboundContent; | ||
|
||
this.sizedStreamSupplier = Objects.requireNonNull(sizedStreamSupplier, "sizedStreamSupplier"); | ||
} | ||
|
||
protected abstract T processStream(InputStream stream) throws IOException; | ||
protected abstract T processStream(InputStream stream); | ||
|
||
@Override | ||
public T call() throws IOException { | ||
URL u = new URL(url); | ||
InputStream stream = null; | ||
final String protocol = u.getProtocol(); | ||
if(protocol.equals("http") || protocol.equals("https")) { | ||
HttpURLConnection conn = (HttpURLConnection) u.openConnection(); | ||
conn.setRequestMethod(method); | ||
conn.setDoInput(true); | ||
|
||
for (Map.Entry<String,String> entry : headers.entrySet()) { | ||
String key = entry.getKey(); | ||
String value = entry.getValue(); | ||
if (value != null && !value.equals("")) | ||
conn.setRequestProperty(key, value); | ||
} | ||
if(outboundContent != null && method.equals("POST")) { | ||
conn.setDoOutput(true); | ||
byte[] outBytes = outboundContent.getBytes("utf-8"); | ||
conn.setRequestProperty("Content-Length", String.valueOf(outBytes.length)); | ||
OutputStream out = conn.getOutputStream(); | ||
out.write(outBytes); | ||
out.close(); | ||
} | ||
conn.connect(); | ||
fileSize = conn.getContentLength(); | ||
setProgressMax(fileSize); | ||
responseHeaders = conn.getHeaderFields(); | ||
|
||
stream = new ProgressInputStream(conn.getInputStream()); | ||
} else { // protocol is something other than http... | ||
URLConnection con = u.openConnection(); | ||
setProgressMax(con.getContentLength()); | ||
stream = new ProgressInputStream(con.getInputStream()); | ||
} | ||
SizedStream sizedStream = sizedStreamSupplier.get(); | ||
|
||
setProgressMax(sizedStream.size); | ||
|
||
try { | ||
try (ProgressInputStream stream = new ProgressInputStream(sizedStream.stream)) { | ||
return processStream(stream); | ||
} | ||
finally { | ||
stream.close(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have to continue closing the stream when background loading is happening with URL? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that the resource is getting closed. |
||
} | ||
} | ||
|
||
protected class ProgressInputStream extends BufferedInputStream { | ||
|
@@ -146,26 +106,4 @@ public int read(byte b[]) throws IOException { | |
return bytes; | ||
} | ||
} | ||
|
||
public void setHeader(String header, String value) { | ||
headers.put(header, value); | ||
} | ||
|
||
public String getResponseHeader(String header) { | ||
String value = null; | ||
List<String> list = responseHeaders.get(header); | ||
// return a csv of the strings. | ||
if(list != null) { | ||
StringBuilder sb = new StringBuilder(); | ||
Iterator iter = list.iterator(); | ||
while(iter.hasNext()) { | ||
sb.append(iter.next()); | ||
if(iter.hasNext()) { | ||
sb.append(','); | ||
} | ||
} | ||
value = sb.toString(); | ||
} | ||
return value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,9 @@ | |
import javafx.stage.Window; | ||
import java.io.File; | ||
import java.io.InputStream; | ||
import java.net.HttpURLConnection; | ||
import java.net.URL; | ||
import java.net.URLConnection; | ||
import java.nio.Buffer; | ||
import java.nio.ByteBuffer; | ||
import java.nio.IntBuffer; | ||
|
@@ -92,6 +95,8 @@ | |
import com.sun.javafx.perf.PerformanceTracker; | ||
import com.sun.javafx.runtime.async.AbstractRemoteResource; | ||
import com.sun.javafx.runtime.async.AsyncOperationListener; | ||
import com.sun.javafx.runtime.async.AbstractRemoteResource.SizedStream; | ||
import com.sun.javafx.runtime.async.AbstractRemoteResource.SizedStreamSupplier; | ||
import com.sun.javafx.scene.text.TextLayoutFactory; | ||
import com.sun.javafx.sg.prism.NGNode; | ||
import com.sun.javafx.tk.CompletionListener; | ||
|
@@ -813,10 +818,42 @@ private float getMaxRenderScale() { | |
return new PrismImageLoader2(stream, width, height, preserveRatio, smooth); | ||
} | ||
|
||
@Override public AbstractRemoteResource<? extends ImageLoader> loadImageAsync( | ||
AsyncOperationListener listener, String url, | ||
@Override public AbstractRemoteResource<ImageLoader> loadImageAsync( | ||
AsyncOperationListener<ImageLoader> listener, String url, | ||
double width, double height, boolean preserveRatio, boolean smooth) { | ||
return new PrismImageLoader2.AsyncImageLoader(listener, url, width, height, preserveRatio, smooth); | ||
|
||
SizedStreamSupplier sizedStreamSupplier = () -> { | ||
URL u = new URL(url); | ||
String protocol = u.getProtocol(); | ||
|
||
if(protocol.equals("http") || protocol.equals("https")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: add a space after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor suggestion: |
||
HttpURLConnection conn = (HttpURLConnection) u.openConnection(); | ||
hjohn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
conn.setRequestMethod("GET"); | ||
conn.connect(); | ||
|
||
long size = conn.getContentLengthLong(); | ||
|
||
return new SizedStream(conn.getInputStream(), size); | ||
} | ||
|
||
// protocol is something other than http... | ||
URLConnection conn = u.openConnection(); | ||
long size = conn.getContentLengthLong(); | ||
|
||
return new SizedStream(conn.getInputStream(), size); | ||
}; | ||
|
||
return new PrismImageLoader2.AsyncImageLoader(listener, sizedStreamSupplier, width, height, preserveRatio, smooth); | ||
} | ||
|
||
@Override public AbstractRemoteResource<ImageLoader> loadImageAsync( | ||
AsyncOperationListener<ImageLoader> listener, InputStream stream, | ||
double width, double height, boolean preserveRatio, boolean smooth) { | ||
|
||
SizedStreamSupplier sizedStreamSupplier = () -> new SizedStream(stream, -1); | ||
|
||
return new PrismImageLoader2.AsyncImageLoader(listener, sizedStreamSupplier, width, height, preserveRatio, smooth); | ||
} | ||
|
||
// Note that this method should only be called by PlatformImpl.runLater | ||
|
Uh oh!
There was an error while loading. Please reload this page.