JDK-8157413 : Multiple WebView behavior looks to collide when loading the same URL
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: 8u92,9
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2016-05-19
  • Updated: 2017-07-31
  • Resolved: 2017-07-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10
10Resolved
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
When in a JavaFX application you have multiple WebViews that load the same URL ; the changes reported by a listener on : view.getEngine().getLoadWorker().stateProperty().addListener(...) are totally incoherent.

The same code works well when the URL are totally different.

The bug occurs in all the versions I have tested 1.8.0_92, 1.8.0_74 & 1.8.0_102-ea-b01.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
execute the attached class and verify the logs ; incoherent states & missing DOM object are reported.

The class support 3 modes, defined by the value of urlMode variable line 34.

when urlMode = UrlMode.UNIQUE => multiple views opening the exact same URL
when urlMode = UrlMode.UNIQUE_DIFF_PARAMETER=> multiple views opening the same URL with different parameters (html app
scenario)
when urlMode = UrlMode.MULTIPLE => multiple views opening different URLs

Only when the URL are really different then no errors are reported , otherwise the listener receives incoherent information:
- bad order of state changes
- multiple times the same state
- missing DOM document object when state is succeed

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Even when multiple webviews work on the same URL:
- the reported states of the load worker are coherent
- the dom object is available when the webpage succeed to load
ACTUAL -
Incoherent results when loading several time the same URL

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package com.agfa.apps.bug.javafx;

import org.w3c.dom.Document;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class MultipleWebViewBug extends Application {
    public static String[] uniqueURL = new String[] { "https://www.reddit.com/r/javafx" };

    public static String[] manyURLS = new String[] { "http://www.google.com",
            "http://stackoverflow.com/questions/29779219/java-fx-loading-multiple-webpages-in-webview-at-a-time",
            "http://oracle.com", "http://mysql.com", "https://www.reddit.com/r/javafx", "http://spring.io", "http://r-project.org",
            "http://tomcat.apache.org" };

    @Override
    public void start(final Stage primaryStage) {
        final FlowPane root = new FlowPane();
        final Scene scene = new Scene(root, 780, 780);
        primaryStage.setScene(scene);
        primaryStage.show();

        
        // ++++++++++++++++++++++++++++++++
        // Change this for different behaviors
        // ++++++++++++++++++++++++++++++++
        UrlMode urlMode = UrlMode.UNIQUE;
        
        for (int i = 0; i < manyURLS.length; i++) {
            root.getChildren().add(newView(i, retrieveURL(i, urlMode)));
        }
    }


    public static void main(final String[] args) {
        launch(args);
    }
    
    private String retrieveURL(int i, UrlMode mode) {
        switch (mode) {
            case UNIQUE:
                return uniqueURL[0];
            case UNIQUE_DIFF_PARAMETER:
                return uniqueURL[0] + "?nb="+i;
            case MULTIPLE:
                return manyURLS[i%manyURLS.length];
        }
        throw new IllegalStateException("enum value not handled: " + mode);
    }

    private WebView newView(int number, String url) {
        final WebView view = new WebView();
        view.setPrefSize(250.0, 250.0);
        addStateChangeListener("view-" + number, view);
        view.getEngine().load(url);
        return view;
    }

    private void addStateChangeListener(final String webViewName, final WebView view) {
        view.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(final ObservableValue<? extends Worker.State> ov, final Worker.State oldState, final Worker.State newState) {
                logState(webViewName, oldState, newState, view.getEngine().getDocument());
            }
        });
    }

    private void logState(final String webViewName, final Worker.State oldState, final Worker.State newState, final Document dom) {
        // log state change
        final String domPresence = dom == null ? "NO DOM" : "DOM OK";
        System.out.println("> INFO  " + webViewName + " dom=" + domPresence + ", oldState=" + oldState + ", newState=" + newState);

        // Log if state SUCCEEDED but Document is null
        if (newState == Worker.State.SUCCEEDED && dom == null) {
            System.out.println("! ERROR " + webViewName + " state SUCCEEDED with null document");
        }

        if (oldState == State.READY && newState == State.SCHEDULED) {
            return;
        }
        if (oldState == State.SCHEDULED && newState == State.RUNNING) {
            return;
        }
        if (oldState == State.RUNNING && newState == State.SUCCEEDED) {
            return;
        }
        // Log incoherent state transitions
        System.out.println("! ERROR " + webViewName + " Incoherent state change from " + oldState + " to " + newState);
    }
    
    private enum UrlMode {
        UNIQUE,
        UNIQUE_DIFF_PARAMETER,
        MULTIPLE;
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Do not allow multiple webviews to load in parallel :-(


Comments
Fixed as part of JDK-8183292. Tested on Windows, OSX and Linux.
31-07-2017

8 GA (B-132) : Reproducible 8u60 (B-32) : Reproducible
12-07-2016