fr.isen.browser5.Util.UrlLoader.java Source code

Java tutorial

Introduction

Here is the source code for fr.isen.browser5.Util.UrlLoader.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.isen.browser5.Util;

import fr.isen.browser5.Model.HistoryEntry;
import fr.isen.browser5.Util.CustomDAO.GlobalHistoryDAO;
import fr.isen.browser5.View.ElementVisitor;
import fr.isen.browser5.View.TabView;
import net.sf.image4j.codec.ico.ICODecoder;
import org.apache.commons.io.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.DataNode;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author baptiste
 */
public class UrlLoader {
    private final TabView tabView;
    private ElementVisitor elementVisitor;
    private GlobalHistoryDAO globalHistoryDAO = new GlobalHistoryDAO();
    private HttpURLConnection connection;
    private Document doc;
    private URL pageUrl = null;
    private String httpCharset;
    private byte[] httpData;
    private String script = "";

    public UrlLoader(TabView tabView) {
        this.tabView = tabView;
    }

    public void loadInThread(final String url, final Object... args) {
        Runnable urlLoaderRunnable = new Runnable() {
            public void run() {
                load(url, args);
            }
        };
        Thread thread = new Thread(urlLoaderRunnable);
        thread.setDaemon(true);
        thread.start();
    }

    private void load(String url, Object... args) {
        String method = null, action = null;
        HashMap<String, String> params = null;
        if (args.length == 3) {
            method = (String) args[0];
            action = (String) args[1];
            params = (HashMap<String, String>) args[2];
        }
        try {
            url = Str.checkProtocol(url);
            String urlParameters = "";
            if (method != null) {
                url = Str.removeLastSlash(url);
                if (action.startsWith("/")) {
                    action = action.substring(1);
                }
                if (action.startsWith("http://") || action.startsWith("https://")) {
                    url = action;
                } else {
                    url += "/" + action;
                }

                int i = 0;
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    urlParameters += entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
                    if (!(i++ == params.size() - 1)) {
                        urlParameters += "&";
                    }
                }

                if (method.equals("GET")) {
                    url += "?" + urlParameters;
                }
            } else {
                method = "GET";
            }

            System.out.println();
            System.out.println("Loading url: " + url);

            URL obj = new URL(url);
            connection = (HttpURLConnection) obj.openConnection();
            connection.setReadTimeout(10000);
            connection.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
            connection.addRequestProperty("User-Agent", "Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1");
            connection.setRequestMethod(method);

            if (method.equals("POST")) {
                byte[] postData = urlParameters.getBytes(Charset.forName("UTF-8"));
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                connection.setRequestProperty("Content-Length", "" + Integer.toString(postData.length));
                connection.setRequestProperty("Content-Language", "en-US");
                connection.setDoInput(true);
                connection.setDoOutput(true);
                try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
                    wr.write(postData);
                }
            }

            if (handleRedirects())
                return;

            handleConnectionResponse();
        } catch (IOException ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(null, ex.getMessage(), ex.getClass().getSimpleName(),
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    private boolean handleRedirects() throws IOException {
        int status = connection.getResponseCode();
        if (status == 301 || status == 302 || status == 303) {
            String redirectUrl = connection.getHeaderField("Location");
            System.out.println("Redirect to: " + redirectUrl);
            load(redirectUrl);
            return true;
        }
        return false;
    }

    private String getCharset(String contentType) {
        String charset = null;
        String[] parts = contentType.split(";");
        for (String part : parts) {
            if (part.contains("charset=")) {
                charset = part.split("=")[1].trim();
            }
        }
        return charset;
    }

    private void handleConnectionResponse() throws IOException {
        boolean isError = connection.getResponseCode() >= 400;
        InputStream is = isError ? connection.getErrorStream() : connection.getInputStream();
        httpCharset = getCharset(connection.getContentType());
        if (httpCharset == null)
            httpCharset = "UTF-8";
        try {
            Charset.forName(httpCharset);
        } catch (UnsupportedCharsetException ex) {
            ex.printStackTrace();
            httpCharset = "UTF-8";
        }
        httpData = IOUtils.toByteArray(is);
        pageUrl = connection.getURL();
        parseResponse();
    }

    public void parseResponse() {
        doc = null;
        try {
            System.out.println("Response url: " + pageUrl);
            tabView.syncTabHistory(pageUrl.toString());
            tabView.removeAll();
            if (tabView.getCurrentFrame().getTabPane().getSelectedIndex() == tabView.getCurrentTabIndex()) {
                tabView.getCurrentFrame().setUrl(pageUrl.toString());
            }
            tabView.setUrl(pageUrl);
            checkHtmlCharset();
            tabView.setDoc(doc);
            setTabTitleFavicon();
            tabView.getCurrentScrollPane().getViewport().setBackground(Color.WHITE);
            tabView.getDevView().clear();
            elementVisitor = new ElementVisitor(tabView);
            doc.body().traverse(elementVisitor);
            getScripts();
            tabView.removeAll();
            movePanel();
            tabView.getDevView().load(tabView);
            tabView.getDevView().executeScripts(script);
            tabView.revalidate();
            tabView.repaint();
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e.getMessage(), e.getClass().getSimpleName(),
                    JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getScripts() {
        Elements scriptElements = doc.getElementsByTag("script");
        for (Element element : scriptElements) {
            for (DataNode node : element.dataNodes()) {
                script += node.getWholeData();
            }
        }
    }

    public void reparseDoc(Document document) {
        try {
            doc = document;
            elementVisitor = new ElementVisitor(tabView);
            doc.body().traverse(elementVisitor);
            tabView.removeAll();
            movePanel();
            tabView.getDevView().getTabElements().print(tabView);
            tabView.revalidate();
            tabView.repaint();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void movePanel() {
        JPanel panel = elementVisitor.getPanel();
        int count = panel.getComponentCount();
        for (int i = 0; i < count; i++) {
            tabView.add(panel.getComponent(0));
        }
    }

    public void checkHtmlCharset() throws IOException {
        doc = Jsoup.parse(new ByteArrayInputStream(httpData), httpCharset, pageUrl.toString());
        // HTML meta tag
        String htmlContentType = doc.select("meta[http-equiv=\"Content-Type\"]").attr("content");
        String htmlCharset = getCharset(htmlContentType);
        // HTML5 meta tag
        String html5Charset = doc.select("meta[charset]").attr("charset");
        // XML encoding tag
        Matcher m = Pattern.compile("xml version=\"(.*)\" encoding=\"(.*)\"").matcher(doc.toString());
        String xmlCharset = null;
        if (m.find())
            xmlCharset = m.group(2);

        String charsetName = null;
        if (htmlCharset != null) {
            charsetName = htmlCharset;
        } else if (!html5Charset.isEmpty()) {
            charsetName = html5Charset;
        } else if (xmlCharset != null) {
            charsetName = xmlCharset;
        }

        if (charsetName != null && !charsetName.equals(httpCharset)) {
            try {
                Charset.forName(charsetName);
            } catch (UnsupportedCharsetException ex) {
                ex.printStackTrace();
                return;
            }
            doc = Jsoup.parse(new ByteArrayInputStream(httpData), htmlCharset, pageUrl.toString());
        }
    }

    public void setTabTitleFavicon() {
        String title = doc.title();
        title = Str.shortenString(title, 12);
        int tabIndex = tabView.getCurrentTabIndex();
        JPanel tabPanel = (JPanel) tabView.getCurrentFrame().getTabPane().getTabComponentAt(tabIndex);
        JLabel titleLabel = (JLabel) tabPanel.getComponent(0);
        titleLabel.setText(title);

        String baseUrl = pageUrl.getProtocol() + "://" + pageUrl.getHost();
        Element element = doc.head().select("link[href~=.*\\.(ico|png)]").first();
        String favicoUrlStr = "";
        if (element != null) {
            favicoUrlStr = element.attr("abs:href");
        } else {
            element = doc.head().select("meta[itemprop=image]").first();
            if (element != null) {
                favicoUrlStr = baseUrl + element.attr("content");
            }
        }

        ImageIcon icon = null;
        try {
            if (!favicoUrlStr.isEmpty()) {
                if (favicoUrlStr.endsWith(".ico")) {
                    java.util.List<BufferedImage> imgs = ICODecoder.read(new URL(favicoUrlStr).openStream());
                    icon = new ImageIcon(imgs.get(0));
                } else {
                    icon = new ImageIcon(new URL(favicoUrlStr));
                }
                icon = new ImageIcon(icon.getImage().getScaledInstance(16, 16, Image.SCALE_DEFAULT));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        titleLabel.setIcon(icon);

        HistoryEntry historyEntry = new HistoryEntry(title, pageUrl.toString(), Instant.now().getEpochSecond(),
                icon, -1L);
        globalHistoryDAO.create(historyEntry);
    }
}