Java tutorial
/* * 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); } }