| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.update.internal.configurator.branding; |
| |
| import java.io.*; |
| import java.net.*; |
| import java.text.MessageFormat; // Can't use ICU, possible launch problem? |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.MissingResourceException; |
| import java.util.Properties; |
| import java.util.PropertyResourceBundle; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.update.internal.configurator.Messages; |
| import org.eclipse.update.internal.configurator.Utils; |
| import org.osgi.framework.*; |
| |
| /** |
| * Reads the information found in an "INI" file. This file must be in a |
| * standard Java properties format. A properties file may also be provided |
| * to NL values in the INI file - values must start with the % prefix. A |
| * mapping file may also be provided that contains "fill-ins" for the |
| * properties file - format being "n = some text", where n is a number. |
| */ |
| public class IniFileReader { |
| private static final String PID = "org.eclipse.update.configurator"; //$NON-NLS-1$ |
| private static final Status OK_STATUS = new Status(IStatus.OK, PID, 0, "", null); //$NON-NLS-1$ |
| private static final String KEY_PREFIX = "%"; //$NON-NLS-1$ |
| private static final String KEY_DOUBLE_PREFIX = "%%"; //$NON-NLS-1$ |
| private static final String NLS_TAG = "$nl$"; //$NON-NLS-1$ |
| |
| private String featureId; |
| private String pluginId; |
| private String iniFilename; |
| private String propertiesFilename; |
| private String mappingsFilename; |
| private Properties ini = null; |
| private PropertyResourceBundle properties = null; |
| private Object[] mappings = null; |
| private Bundle bundle; |
| |
| /** |
| * Creates an INI file reader that can parse the contents into key,value pairs. |
| * |
| * @param featureId the unique identifier of the feature, must not be <code>null</code> |
| * @param pluginId the unique identifier of the feature plug-in, must not be <code>null</code> |
| * @param iniFilename the INI file name, must not be <code>null</code> |
| * @param propertiesFilename the properties filename, can be <code>null</code> if not required |
| * @param mappingsFilename the mappings filename, can be <code>null</code> if not required |
| */ |
| public IniFileReader(String featureId, String pluginId, String iniFilename, String propertiesFilename, String mappingsFilename) { |
| super(); |
| |
| if (featureId == null || pluginId == null || iniFilename == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| this.featureId = featureId; |
| this.pluginId = pluginId; |
| this.iniFilename = iniFilename; |
| this.propertiesFilename = propertiesFilename; |
| this.mappingsFilename = mappingsFilename; |
| } |
| |
| /** |
| * Read the contents of the INI, properties, and mappings files. |
| * Does nothing if the content has already been read and parsed. |
| * |
| * @return an <code>IStatus</code> indicating the success or failure |
| * of reading and parsing the INI file content |
| */ |
| public IStatus load() { |
| if (ini != null) |
| return OK_STATUS; |
| |
| // attempt to locate the corresponding plugin |
| bundle = Utils.getBundle(pluginId); |
| if (bundle == null || bundle.getState() == Bundle.UNINSTALLED || bundle.getState() == Bundle.INSTALLED) { |
| bundle = null; // make it null for other test down the road |
| String message = NLS.bind(Messages.IniFileReader_MissingDesc, (new String[] { featureId })); |
| return new Status(IStatus.ERROR, PID, 0, message, null); |
| } |
| |
| // Determine the ini file location |
| URL iniURL = null; |
| IOException ioe = null; |
| iniURL = FileLocator.find(bundle, new Path(NLS_TAG).append(iniFilename), null); |
| if (iniURL == null) { |
| String message = NLS.bind(Messages.IniFileReader_OpenINIError, (new String[] { iniFilename })); |
| return new Status(IStatus.ERROR, PID, 0, message, ioe); |
| } |
| |
| // Determine the properties file location |
| URL propertiesURL = null; |
| if (propertiesFilename != null & propertiesFilename.length() > 0) { |
| propertiesURL = FileLocator.find(bundle, new Path(NLS_TAG).append(propertiesFilename), null); |
| } |
| |
| // Determine the mappings file location |
| URL mappingsURL = null; |
| if (mappingsFilename != null && mappingsFilename.length() > 0) { |
| mappingsURL = FileLocator.find(bundle, new Path(NLS_TAG).append(mappingsFilename), null); |
| } |
| |
| // OK to pass null properties and/or mapping file |
| return load(iniURL, propertiesURL, mappingsURL); |
| } |
| |
| /** |
| * Returns the string value for the given key, or <code>null</code>. |
| * The string value is NLS if requested. |
| * |
| * @return the string value for the given key, or <code>null</code> |
| */ |
| public String getString(String key, boolean doNls, Hashtable<String, String> runtimeMappings) { |
| if (ini == null) |
| return null; |
| String value = ini.getProperty(key); |
| if (value != null && doNls) |
| return getResourceString(value, runtimeMappings); |
| return value; |
| } |
| |
| |
| /** |
| * Returns a URL for the given key, or <code>null</code>. |
| * |
| * @return a URL for the given key, or <code>null</code> |
| */ |
| public URL getURL(String key) { |
| if (ini == null) |
| return null; |
| |
| URL url = null; |
| String fileName = ini.getProperty(key); |
| if (fileName != null) { |
| if (bundle == null) |
| return null; |
| url = FileLocator.find(bundle, new Path(fileName), null); |
| } |
| return url; |
| } |
| |
| /** |
| * Returns a array of URL for the given key, or <code>null</code>. The |
| * property value should be a comma separated list of urls, tokens for |
| * which bundle cannot build an url will have a null entry. |
| * |
| * @param key name of the property containing the requested urls |
| * @return a URL for the given key, or <code>null</code> |
| * @since 3.0 |
| */ |
| public URL[] getURLs(String key) { |
| if (ini == null || bundle == null) |
| return null; |
| |
| String value = ini.getProperty(key); |
| if (value == null) |
| return null; |
| |
| StringTokenizer tokens = new StringTokenizer(value, ","); //$NON-NLS-1$ |
| ArrayList<URL> array = new ArrayList<>(10); |
| while (tokens.hasMoreTokens()) { |
| String str = tokens.nextToken().trim(); |
| array.add(FileLocator.find(bundle, new Path(str), null)); |
| } |
| |
| URL[] urls = new URL[array.size()]; |
| array.toArray(urls); |
| return urls; |
| } |
| |
| /** |
| * Returns the feature plugin label, or <code>null</code>. |
| * |
| * @return the feature plugin lable, or <code>null</code> if none. |
| */ |
| public String getFeaturePluginLabel() { |
| if (bundle == null) |
| return null; |
| return bundle.getHeaders().get(Constants.BUNDLE_NAME); |
| } |
| |
| /** |
| * Returns the provider name for this feature, or <code>null</code>. |
| * |
| * @return the provider name for this feature, or <code>null</code> |
| */ |
| public String getProviderName() { |
| if (bundle == null) |
| return null; |
| return bundle.getHeaders().get(Constants.BUNDLE_VENDOR); |
| } |
| |
| /* |
| * Returns a resource string corresponding to the given argument |
| * value and bundle. |
| * If the argument value specifies a resource key, the string |
| * is looked up in the given resource bundle. If the argument does not |
| * specify a valid key, the argument itself is returned as the |
| * resource string. The key lookup is performed against the |
| * specified resource bundle. If a resource string |
| * corresponding to the key is not found in the resource bundle |
| * the key value, or any default text following the key in the |
| * argument value is returned as the resource string. |
| * A key is identified as a string begining with the "%" character. |
| * Note that the "%" character is stripped off prior to lookup |
| * in the resource bundle. |
| * <p> |
| * For example, assume resource bundle plugin.properties contains |
| * name = Project Name |
| * <pre> |
| * <li>getResourceString("Hello World") returns "Hello World"</li> |
| * <li>getResourceString("%name") returns "Project Name"</li> |
| * <li>getResourceString("%name Hello World") returns "Project Name"</li> |
| * <li>getResourceString("%abcd Hello World") returns "Hello World"</li> |
| * <li>getResourceString("%abcd") returns "%abcd"</li> |
| * <li>getResourceString("%%name") returns "%name"</li> |
| * <li>getResourceString(<code>null</code>) returns <code>null</code></li> |
| * </pre> |
| * </p> |
| * |
| * @param value the value or <code>null</code> |
| * @param runtimeMappings runtime mappings or <code>null</code> |
| * @return the resource string |
| */ |
| public String getResourceString(String value, Hashtable<String, String> runtimeMappings) { |
| |
| if (value == null) |
| return null; |
| String s = value.trim(); |
| |
| if (!s.startsWith(KEY_PREFIX)) |
| return s; |
| |
| if (s.startsWith(KEY_DOUBLE_PREFIX)) |
| return s.substring(1); |
| |
| int ix = s.indexOf(" "); //$NON-NLS-1$ |
| String key = ix == -1 ? s : s.substring(0, ix); |
| String dflt = ix == -1 ? s : s.substring(ix + 1); |
| |
| if (properties == null) |
| return dflt; |
| |
| String result = null; |
| try { |
| result = properties.getString(key.substring(1)); |
| } catch (MissingResourceException e) { |
| return dflt; |
| } |
| if (runtimeMappings != null) { |
| for (Enumeration<String> e = runtimeMappings.keys(); e.hasMoreElements();) { |
| String keyValue = e.nextElement(); |
| int i = result.indexOf(keyValue); |
| if (i != -1) { |
| String s1 = result.substring(0,i); |
| String s2 = runtimeMappings.get(keyValue); |
| String s3 = result.substring(i+keyValue.length()); |
| result = s1 + s2 + s3; |
| } |
| } |
| } |
| |
| if (result.indexOf('{') != -1) { |
| // We test for the curly braces since due to NL issues we do not |
| // want to use MessageFormat unless we have to. |
| try { |
| result = MessageFormat.format(result, mappings); |
| } catch (IllegalArgumentException e) { |
| //ignore and return string without bound parameters |
| } |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Read the contents of the ini, properties, and mappings files. |
| */ |
| private IStatus load(URL iniURL, URL propertiesURL, URL mappingsURL) { |
| |
| InputStream is = null; |
| try { |
| is = iniURL.openStream(); |
| ini = new Properties(); |
| ini.load(is); |
| } catch (IOException e) { |
| ini = null; |
| String message = NLS.bind(Messages.IniFileReader_ReadIniError, (new String[] { iniURL.toExternalForm() })); |
| return new Status(IStatus.ERROR, PID, 0, message, e); |
| } finally { |
| try { |
| if (is != null) |
| is.close(); |
| } catch (IOException e) { |
| } |
| } |
| |
| if (propertiesURL != null) { |
| is = null; |
| try { |
| is = propertiesURL.openStream(); |
| properties = new PropertyResourceBundle(is); |
| } catch (IOException e) { |
| properties = null; |
| String message = NLS.bind(Messages.IniFileReader_ReadPropError, (new String[] { propertiesURL.toExternalForm() })); |
| return new Status(IStatus.ERROR, PID, 0, message, e); |
| } finally { |
| try { |
| if (is != null) |
| is.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| |
| PropertyResourceBundle bundle = null; |
| if (mappingsURL != null) { |
| is = null; |
| try { |
| is = mappingsURL.openStream(); |
| bundle = new PropertyResourceBundle(is); |
| } catch (IOException e) { |
| bundle = null; |
| String message = NLS.bind(Messages.IniFileReader_ReadMapError, (new String[] { mappingsURL.toExternalForm() })); |
| return new Status(IStatus.ERROR, PID, 0, message, e); |
| } finally { |
| try { |
| if (is != null) |
| is.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| |
| ArrayList<String> mappingsList = new ArrayList<>(); |
| if (bundle != null) { |
| boolean found = true; |
| int i = 0; |
| while (found) { |
| try { |
| mappingsList.add(bundle.getString(Integer.toString(i))); |
| } catch (MissingResourceException e) { |
| found = false; |
| } |
| i++; |
| } |
| } |
| mappings = mappingsList.toArray(new String[mappingsList.size()]); |
| |
| return OK_STATUS; |
| } |
| } |