/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools; import java.awt.Desktop; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Action; import javax.swing.event.HyperlinkListener; import com.rapidminer.gui.MainFrame; import com.rapidminer.gui.RapidMinerGUI; import com.rapidminer.gui.actions.SettingsAction; import com.rapidminer.gui.dialog.BrowserUnavailableDialogFactory; import com.rapidminer.gui.tools.dialogs.ButtonDialog; import com.rapidminer.operator.Operator; import com.rapidminer.operator.OperatorCreationException; /** * Convenience class for invoking certain actions from URLs, e.g. from inside a * {@link HyperlinkListener}. URLs of the form "rm://actionName" will be interpreted. Actions can * register themselves by invoking {@link RMUrlHandler#register(String, Action)}. * * @author Simon Fischer * */ public class RMUrlHandler { public static final String URL_PREFIX = "rm://"; public static final String PREFERENCES_URL = URL_PREFIX + "preferences"; private static final Map<String, Action> ACTION_MAP = new HashMap<>(); private static final Logger LOGGER = Logger.getLogger(RMUrlHandler.class.getCanonicalName()); static { register("preferences", new SettingsAction()); } /** * * @return true iff we understand the url. */ public static boolean handleUrl(String url) { if (url.startsWith(URL_PREFIX)) { String suffix = url.substring(URL_PREFIX.length()); if (suffix.startsWith("opdoc/")) { String opName = suffix.substring("opdoc/".length()); Operator op; try { op = OperatorService.createOperator(opName); RapidMinerGUI.getMainFrame().getOperatorDocViewer().setDisplayedOperator(op); } catch (OperatorCreationException e) { LogService.getRoot().log(Level.WARNING, I18N.getMessage(LogService.getRoot().getResourceBundle(), "com.rapidminer.tools.RMUrlHandler.creating_operator_error", opName), e); } return true; } if (suffix.startsWith("operator/")) { String opName = suffix.substring("operator/".length()); MainFrame mainFrame = RapidMinerGUI.getMainFrame(); mainFrame.selectAndShowOperator(mainFrame.getProcess().getOperator(opName), true); return true; } Action action = ACTION_MAP.get(suffix); if (action != null) { action.actionPerformed(null); } else { LogService.getRoot().log(Level.WARNING, "com.rapidminer.tools.RMUrlHandler.no_action_associated_with_url", url); } return true; // we didn't make it, but no one else can, so we return true. } else if (url.startsWith("http://") || url.startsWith("https://")) { openInBrowser(url); return true; } else { return false; } } public static void register(String name, Action action) { ACTION_MAP.put(name, action); } /** * On systems where Desktop.getDesktop().browse() does not work for http://, creates an HTML * page which redirects to the given URI and calls Desktop.browse() with this file through the * file:// url which seems to work better, at least for KDE. * * @deprecated Replaced by {@link #openInBrowser(URI)} */ @Deprecated public static void browse(URI uri) throws IOException { if (Desktop.isDesktopSupported()) { try { Desktop.getDesktop().browse(uri); } catch (IOException e) { File tempFile = File.createTempFile("rmredirect", ".html"); tempFile.deleteOnExit(); FileWriter out = new FileWriter(tempFile); try { out.write(String.format( "<!DOCTYPE html>\n" + "<html><meta http-equiv=\"refresh\" content=\"0; URL=%s\"><body>You are redirected to %s</body></html>", uri.toString(), uri.toString())); } finally { out.close(); } Desktop.getDesktop().browse(tempFile.toURI()); } catch (UnsupportedOperationException e1) { showBrowserUnavailableMessage(uri.toString()); } } else { showBrowserUnavailableMessage(uri.toString()); } } /** * Tries to open an URL in the system browser * <p> * Fallback: Shows the URL in a dialog * </p> * * @param uri */ public static void openInBrowser(URL url) { try { URI uri = url.toURI(); openInBrowser(uri); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid URL: " + url.toString(), e); } } /** * Tries to open an URI String in the system browser * <p> * Fallback: Shows the URI String in a dialog * </p> * * @param uri */ public static void openInBrowser(String uriString) { try { URI uri = new URI(uriString); openInBrowser(uri); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid URI String: " + uriString, e); } } /** * Tries to open an URI in the system browser * <p> * Fallback: Shows the URI String in a dialog * </p> */ public static void openInBrowser(URI uri) { if (Desktop.isDesktopSupported()) { try { Desktop.getDesktop().browse(uri); } catch (IOException e) { openInBrowserWithTempFile(uri); } } else { showBrowserUnavailableMessage(uri.toString()); } } /** * Browse the uri using a local temp file * <p> * On systems where Desktop.getDesktop().browse() does not work for http://, creates an HTML * page which redirects to the given URI and calls Desktop.browse() with this file through the * file:// url which seems to work better, at least for KDE. * </p> * * @param uri */ private static void openInBrowserWithTempFile(URI uri) { try { File tempFile = File.createTempFile("rmredirect", ".html"); tempFile.deleteOnExit(); try (FileWriter out = new FileWriter(tempFile)) { out.write(String.format( "<!DOCTYPE html>\n" + "<html><meta http-equiv=\"refresh\" content=\"0; URL=%s\"><body>You are redirected to %s</body></html>", uri.toString(), uri.toString())); Desktop.getDesktop().browse(tempFile.toURI()); } } catch (IOException e) { showBrowserUnavailableMessage(uri.toString()); } } /** * Displays the uri in a {@link ButtonDialog} * * @param uri */ private static void showBrowserUnavailableMessage(String uri) { ButtonDialog dialog = BrowserUnavailableDialogFactory.createNewDialog(uri); dialog.setVisible(true); LOGGER.log(Level.SEVERE, "Failed to open web page in browser, browsing is not supported on this platform."); } }