/******************************************************************************* * Copyright (c) 2003, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.intro.impl.model.url; import java.io.ByteArrayOutputStream; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Properties; import org.eclipse.ui.internal.intro.impl.util.Log; import org.eclipse.ui.internal.intro.impl.util.StringUtil; /** * A parser that knows how to parser OOBE action URLs. If URL is a valid intro * url, it will create an instance of the IntroURL class. */ public class IntroURLParser { // private String url_string = null; private boolean hasProtocol = false; private boolean isIntroUrl = false; private URL url_inst; /** * Constructor that gets the URL to parse. */ public IntroURLParser(String url) { // create a URL instance, and parser it for parameters. parseUrl(url); } private void parseUrl(String url) { if (url == null) return; url_inst = null; try { url_inst = new URL(url); } catch (MalformedURLException e) { // not a valid URL. set state. return; } if (url_inst.getProtocol() != null) { // URL has some valid protocol. Check to see if it is an intro url. hasProtocol = true; isIntroUrl = isIntroUrl(url_inst); return; } // not an Intro URL. do nothing. return; } /** * @return Returns the hasProtocol. */ public boolean hasProtocol() { return hasProtocol; } /** * @return Returns the isIntroUrl. */ public boolean hasIntroUrl() { return isIntroUrl; } /** * @return Returns the currebt url Protocol. */ public String getProtocol() { return url_inst.getProtocol(); } /** * @return Returns the currebt url Protocol. */ public String getHost() { return url_inst.getHost(); } /** * Checks to see if tha passed URL is an Intro URL. An intro URL is an http * URL that has the intro plugin id as a host. eg: * "http://org.eclipse.ui.intro/test". * * @param url * @return true if url is an intro URL. */ private boolean isIntroUrl(URL url) { if (!url.getProtocol().equalsIgnoreCase(IntroURL.INTRO_PROTOCOL)) // quick exit. If it is not http, url is not an Intro url. return false; if (url.getHost().equalsIgnoreCase(IntroURL.INTRO_HOST_ID)) return true; return false; } /** * @return Returns the introURL. Will be null if the parsed URL is not an * Intro URL. */ public IntroURL getIntroURL() { IntroURL introURL = null; if (isIntroUrl) { // valid intro URL. Extract the action and parameters. String action = getPathAsAction(url_inst); Properties parameters = getQueryParameters(url_inst); // class instance vars are already populated by now. introURL = new IntroURL(action, parameters); } return introURL; } /** * Retruns the path attribute of the passed URL, stripped out of the leading * "/". Returns null if the url does not have a path. * * @param url * @return */ private String getPathAsAction(URL url) { // get possible action. String action = url.getPath(); // remove leading "/" from path. if (action != null) action = action.substring(1); return action; } /** * Retruns the Query part of the URL as an instance of a Properties class. * * @param url * @return */ public Properties getQueryParameters(URL url) { // parser all query parameters. Properties properties = new Properties(); String query = url.getQuery(); if (query == null) // we do not have any parameters in this URL, return an empty // Properties instance. return properties; // now extract the key/value pairs from the query. String[] params = StringUtil.split(query, "&"); //$NON-NLS-1$ for (int i = 0; i < params.length; i++) { // for every parameter, ie: key=value pair, create a property // entry. we know we have the key as the first string in the array, // and the value as the second array. String[] keyValuePair = StringUtil.split(params[i], "="); //$NON-NLS-1$ if (keyValuePair.length != 2) { Log.warning("Ignoring the following Intro URL parameter: " //$NON-NLS-1$ + params[i]); continue; } String key = urlDecode(keyValuePair[0]); if (key == null) { Log.warning("Failed to URL decode key: " + keyValuePair[0]); //$NON-NLS-1$ continue; } String value = urlDecode(keyValuePair[1]); if (value == null) { Log.warning("Failed to URL decode value: " + keyValuePair[1]); //$NON-NLS-1$ continue; } properties.setProperty(key, value); } return properties; } /* * Note: This was copied and adapted from org.eclipse.help.internal.util.URLCoder */ private static String urlDecode(String encodedURL) { int len = encodedURL.length(); ByteArrayOutputStream os = new ByteArrayOutputStream(len); for (int i = 0; i < len;) { switch (encodedURL.charAt(i)) { case '%': if (len >= i + 3) { os.write(Integer.parseInt(encodedURL.substring(i + 1, i + 3), 16)); } i += 3; break; case '+': // exception from standard os.write(' '); i++; break; default: os.write(encodedURL.charAt(i++)); break; } } return new String(os.toByteArray(), StandardCharsets.UTF_8); } }