Package com.eviware.soapui.support.components

Source Code of com.eviware.soapui.support.components.EnabledWebViewBasedBrowserComponent

/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/

package com.eviware.soapui.support.components;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.rest.actions.oauth.BrowserListener;
import com.eviware.soapui.support.Tools;
import com.eviware.soapui.support.xml.XmlUtils;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.PopupFeatures;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.util.Callback;
import netscape.javascript.*;

import javax.swing.*;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class EnabledWebViewBasedBrowserComponent implements WebViewBasedBrowserComponent {
    public static final String CHARSET_PATTERN = "(.+)(;\\s*charset=)(.+)";
    public static final String DEFAULT_ERROR_PAGE = "<html><body><h1>The page could not be loaded</h1></body></html>";
    private Pattern charsetFinderPattern = Pattern.compile(CHARSET_PATTERN);

    private JPanel panel = new JPanel(new BorderLayout());
    private String errorPage;
    private boolean showingErrorPage;
    public String url;
    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    private java.util.List<BrowserListener> listeners = new ArrayList<BrowserListener>();

    public WebView webView;
    private WebViewNavigationBar navigationBar;
    private String lastLocation;
    private Set<BrowserWindow> browserWindows = new HashSet<BrowserWindow>();

    private JFXPanel browserPanel;
    private PopupStrategy popupStrategy;

    EnabledWebViewBasedBrowserComponent(boolean addNavigationBar, PopupStrategy popupStrategy) {
        this.popupStrategy = popupStrategy;
        initializeWebView(addNavigationBar);
    }

    @Override
    public Component getComponent() {
        return panel;
    }

    private void initializeWebView(boolean addNavigationBar) {
        if (addNavigationBar) {
            navigationBar = new WebViewNavigationBar();
            panel.add(navigationBar.getComponent(), BorderLayout.NORTH);
        }

        final JFXPanel browserPanel = new JFXPanel();
        panel.add(browserPanel, BorderLayout.CENTER);

        WebViewInitialization webViewInitialization = new WebViewInitialization(browserPanel);
        if (Platform.isFxApplicationThread()) {
            webViewInitialization.run();
        } else {
            Platform.runLater(webViewInitialization);
        }
        Runnable runnable = new Runnable() {
            public void run() {
                if (navigationBar != null) {
                    navigationBar.focusUrlField();
                }
            }
        };
        SwingUtilities.invokeLater(runnable);
    }

    private String readDocumentAsString() throws TransformerException {
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

        StringWriter stringWriter = new StringWriter();
        transformer.transform(new DOMSource(getWebEngine().getDocument()),
                new StreamResult(stringWriter));

        return stringWriter.getBuffer().toString().replaceAll("\n|\r", "");
    }

    private void addKeyboardFocusManager(final JFXPanel browserPanel) {
        KeyboardFocusManager kfm = DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager();
        kfm.addKeyEventDispatcher(new KeyEventDispatcher() {
                                      @Override
                                      public boolean dispatchKeyEvent(KeyEvent e) {
                                          if (DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == browserPanel) {
                                              if (e.getID() == KeyEvent.KEY_TYPED && e.getKeyChar() == 10) {
                                                  e.setKeyChar((char) 13);
                                              }
                                          }
                                          return false;
                                      }
                                  }
        );
    }

    @Override
    public void executeJavaScript(final String script) {
        Platform.runLater(new Runnable() {
            public void run() {
                try {
                    webView.getEngine().executeScript(script);
                    for (BrowserListener listener : listeners) {
                        listener.javaScriptExecuted(script, null, null);
                    }
                } catch (Exception e) {
                    SoapUI.log.warn("Error executing JavaScript [" + script + "]", e);
                    for (BrowserListener listener : listeners) {
                        listener.javaScriptExecuted(script, lastLocation, e);
                    }
                }
            }
        });
    }

    @Override
    public void addJavaScriptEventHandler(final String memberName, final Object eventHandler) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                getWebEngine().getLoadWorker().stateProperty().addListener(
                        new ChangeListener<Worker.State>() {
                            public void changed(ObservableValue observableValue, Worker.State oldState, Worker.State newState) {
                                if (newState == Worker.State.SUCCEEDED) {
                                    JSObject window = (JSObject) getWebEngine().executeScript("window");
                                    window.setMember(memberName, eventHandler);
                                }
                            }
                        }
                );
            }
        });
    }

    @Override
    public void close(boolean cascade) {
        if (cascade) {
            for (Iterator<BrowserWindow> iterator = browserWindows.iterator(); iterator.hasNext(); ) {
                iterator.next().close();
                iterator.remove();
            }
        }

        for (BrowserListener listener : listeners) {
            listener.browserClosed();
        }
        release();
    }

    private void release() {
        setContent("");
        browserPanel.setScene(null);
    }

    @Override
    public void setContent(final String contentAsString, final String contentType) {
        if (SoapUI.isBrowserDisabled()) {
            return;
        }
        Platform.runLater(new Runnable() {
            public void run() {

                getWebEngine().loadContent(contentAsString, removeCharsetFrom(contentType));
            }
        });
    }

    private String removeCharsetFrom(String contentType) {
        Matcher matcher = charsetFinderPattern.matcher(contentType);
        return matcher.matches() ? matcher.group(1) : contentType;
    }

    @Override
    public void setContent(final String contentAsString) {
        if (SoapUI.isBrowserDisabled()) {
            return;
        }
        Platform.runLater(new Runnable() {
            public void run() {
                getWebEngine().loadContent(contentAsString);
            }
        });
        pcs.firePropertyChange("content", null, contentAsString);
    }

    private WebEngine getWebEngine() {
        return webView.getEngine();
    }

    public String getContent() {
        return webView == null ? null : XmlUtils.serialize(getWebEngine().getDocument());
    }


    public String getUrl() {
        return url;
    }


    public void setErrorPage(String errorPage) {
        this.errorPage = errorPage;
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        pcs.addPropertyChangeListener(pcl);
    }


    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        pcs.removePropertyChangeListener(pcl);
    }

    @Override
    public void navigate(final String url) {
        navigate(url, DEFAULT_ERROR_PAGE);
    }

    public void navigate(final String url, String errorPage) {
        if (SoapUI.isBrowserDisabled()) {
            return;
        }
        setErrorPage(errorPage);

        this.url = url;

        Platform.runLater(new Runnable() {
            public void run() {
                getWebEngine().load(url);
            }
        });

    }

    @Override
    public void addBrowserStateListener(BrowserListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeBrowserStateListener(BrowserListener listener) {
        listeners.remove(listener);
    }

  /*
     Class used to open a new browser window, used in the popup handler of the component.
   */

    private class BrowserWindow extends JFrame {

        private final EnabledWebViewBasedBrowserComponent browser;

        private BrowserWindow(PopupFeatures popupFeatures) throws HeadlessException {
            super("Browser");
            setIconImages(SoapUI.getFrameIcons());
            browser = new EnabledWebViewBasedBrowserComponent(popupFeatures.hasToolbar(), popupStrategy);
            getContentPane().setLayout(new BorderLayout());
            getContentPane().add(browser.getComponent());
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    browser.close(false);
                }
            });
        }

        public void close() {
            setVisible(false);
            dispose();
            browser.close(true);
            browser.release();
        }

    }

  /*
     The task to initialize the Java FX WebView component. Will be run synchronously if we're already on the
  Java FX event thread, asynchronously if we aren't.
   */

    private class WebViewInitialization implements Runnable {

        public WebViewInitialization(JFXPanel browserPanel) {
            EnabledWebViewBasedBrowserComponent.this.browserPanel = browserPanel;
        }

        public void run() {
            webView = new WebView();

            createPopupHandler();
            listenForLocationChanges();
            listenForStateChanges();

            if (navigationBar != null) {
                navigationBar.initialize(getWebEngine(), EnabledWebViewBasedBrowserComponent.this);
            }
            browserPanel.setScene(createJfxScene());
            addKeyboardFocusManager(browserPanel);
        }

        private Scene createJfxScene() {
            Group jfxComponentGroup = new Group();
            Scene scene = new Scene(jfxComponentGroup);
            webView.prefWidthProperty().bind(scene.widthProperty());
            webView.prefHeightProperty().bind(scene.heightProperty());
            jfxComponentGroup.getChildren().add(webView);
            return scene;
        }

        private void createPopupHandler() {
            switch (popupStrategy) {
                case INTERNAL_BROWSER_NEW_WINDOW:
                    webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
                        @Override
                        public WebEngine call(PopupFeatures pf) {
                            BrowserWindow popupWindow = new BrowserWindow(pf);
                            browserWindows.add(popupWindow);
                            popupWindow.setSize(800, 600);
                            popupWindow.setVisible(true);
                            return popupWindow.browser.getWebEngine();
                        }
                    });
                    break;
                case EXTERNAL_BROWSER:
                    webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
                        @Override
                        public WebEngine call(PopupFeatures pf) {
                            final WebEngine webEngine = new WebEngine();
                            webEngine.locationProperty().addListener(new ChangeListener<String>() {
                                @Override
                                public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
                                    observableValue.removeListener(this);
                                    Platform.runLater(new Runnable() {
                                        @Override
                                        public void run() {
                                            webEngine.loadContent("");
                                        }
                                    });
                                    Tools.openURL(newValue);
                                }
                            });
                            return webEngine;
                        }
                    });
                    break;
                case DISABLED:
                    webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
                        @Override
                        public WebEngine call(PopupFeatures pf) {
                            return null;
                        }
                    });
                    break;
                case INTERNAL_BROWSER_REUSE_WINDOW:
                default:
                    break;
            }
        }

        private void listenForLocationChanges() {
            webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observableValue, String oldLocation,
                                    String newLocation) {
                    lastLocation = newLocation;
                    for (BrowserListener listener : listeners) {
                        listener.locationChanged(newLocation);
                    }
                }
            });
        }

        private void listenForStateChanges() {
            webView.getEngine().getLoadWorker().stateProperty().addListener(
                    new ChangeListener<Worker.State>() {
                        @Override
                        public void changed(ObservableValue value, Worker.State oldState, Worker.State newState) {
                            if (newState == Worker.State.SUCCEEDED) {
                                try {
                                    if (getWebEngine().getDocument() != null) {
                                        String output = readDocumentAsString();
                                        for (BrowserListener listener : listeners) {
                                            listener.contentChanged(output);
                                        }
                                    }
                                } catch (Exception ex) {
                                    SoapUI.logError(ex, "Error processing state change to " + newState);
                                }
                            } else if (newState == Worker.State.FAILED && !showingErrorPage) {
                                try {
                                    showingErrorPage = true;
                                    setContent(errorPage == null ? DEFAULT_ERROR_PAGE : errorPage);
                                } finally {
                                    showingErrorPage = false;
                                }
                            }
                        }
                    }
            );
        }

    }
}
TOP

Related Classes of com.eviware.soapui.support.components.EnabledWebViewBasedBrowserComponent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.