| /******************************************************************************* |
| * Copyright (c) 2008, 2010 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.equinox.internal.p2.touchpoint.eclipse.actions; |
| |
| import java.io.*; |
| import java.util.*; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.equinox.internal.p2.touchpoint.eclipse.*; |
| import org.eclipse.equinox.internal.provisional.frameworkadmin.LauncherData; |
| import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator; |
| import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; |
| import org.eclipse.osgi.util.NLS; |
| |
| public class AddJVMArgumentAction extends ProvisioningAction { |
| public static final String ID = "addJvmArg"; //$NON-NLS-1$ |
| protected static final String STORAGE = "org.eclipse.equinox.internal.p2.touchpoint.eclipse.actions" //$NON-NLS-1$ |
| + File.separator + "jvmargs"; //$NON-NLS-1$ |
| |
| protected static final String XMX = "-Xmx"; //$NON-NLS-1$ |
| protected static final String XMS = "-Xms"; //$NON-NLS-1$ |
| protected static final String XX_MAX_PERM_SIZE = "-XX:MaxPermSize="; //$NON-NLS-1$ |
| protected static final String PREFIX_USER_VALUE = "eclipse.userDefined:"; //$NON-NLS-1$ |
| |
| @Override |
| public IStatus execute(Map<String, Object> parameters) { |
| String jvmArg = (String) parameters.get(ActionConstants.PARM_JVM_ARG); |
| if (jvmArg == null) |
| return Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_JVM_ARG, ID)); |
| return addArg(jvmArg, parameters); |
| } |
| |
| @Override |
| public IStatus undo(Map<String, Object> parameters) { |
| String jvmArg = (String) parameters.get(ActionConstants.PARM_JVM_ARG); |
| if (jvmArg == null) |
| return Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_JVM_ARG, ID)); |
| return RemoveJVMArgumentAction.removeArg(jvmArg, parameters); |
| } |
| |
| protected static String getUserArg(Properties storedValues, String flag) { |
| return storedValues.getProperty(PREFIX_USER_VALUE + flag); |
| } |
| |
| protected static IStatus addArg(String arg, Map<String, Object> parameters) { |
| LauncherData launcherData = ((Manipulator) parameters.get(EclipseTouchpoint.PARM_MANIPULATOR)) |
| .getLauncherData(); |
| File storageArea = (File) parameters.get(ActionConstants.PARM_PROFILE_DATA_DIRECTORY); |
| try { |
| if (arg.startsWith(XMS)) |
| addByteArg(arg, XMS, launcherData, storageArea); |
| else if (arg.startsWith(XMX)) |
| addByteArg(arg, XMX, launcherData, storageArea); |
| else if (arg.startsWith(XX_MAX_PERM_SIZE)) |
| addByteArg(arg, XX_MAX_PERM_SIZE, launcherData, storageArea); |
| else |
| // Argument with a non-byte value, no special handling |
| launcherData.addJvmArg(arg); |
| } catch (IOException e) { |
| return new Status(IStatus.ERROR, Activator.ID, Messages.error_processing_vmargs, e); |
| } catch (IllegalArgumentException e) { |
| return new Status(IStatus.ERROR, Activator.ID, Messages.error_processing_vmargs, e); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| protected static void addByteArg(String arg, String flag, LauncherData launcherData, File storageArea) |
| throws IOException { |
| Properties storedValues = load(storageArea); |
| String currentArg = getCurrentArg(flag, launcherData.getJvmArgs()); |
| |
| // Check for user changes |
| detectUserValue(currentArg, flag, storedValues); |
| validateValue(arg.substring(flag.length())); |
| |
| rememberArg(storedValues, arg.substring(flag.length()), flag); |
| launcherData.removeJvmArg(currentArg); |
| |
| // Set the argument to use & save stored values |
| setToMax(flag, storedValues, launcherData); |
| save(storedValues, storageArea); |
| } |
| |
| // Throws exception if the argument is not a valid byte argument |
| protected static void validateValue(String arg) { |
| getByteValue(arg, getBytePower(arg)); |
| } |
| |
| // Determine if the user has changed config, if so save their value |
| protected static void detectUserValue(String currentValue, String flag, Properties storedValues) { |
| String maxValue = getMaxValue(getArgs(storedValues, flag)); |
| |
| if (currentValue == null) |
| // User has removed value from file |
| setUserArg(storedValues, flag, null); |
| else if (maxValue == null || !maxValue.equals(currentValue.substring(flag.length()))) |
| // User has set an initial value, or modified the file |
| setUserArg(storedValues, flag, currentValue.substring(flag.length())); |
| } |
| |
| protected static String getMaxValue(String[] values) { |
| if (values == null || values.length == 0) |
| return null; |
| |
| int max = 0; |
| for (int i = 1; i < values.length; i++) |
| if (compareSize(values[max], values[i]) < 0) |
| max = i; |
| return values[max]; |
| } |
| |
| protected static void setToMax(String flag, Properties storedValues, LauncherData launcherData) { |
| String maxStored = getMaxValue(getArgs(storedValues, flag)); |
| String userDefined = AddJVMArgumentAction.getUserArg(storedValues, flag); |
| |
| if (maxStored != null || userDefined != null) { |
| // Replacement is available either stored, or user defined |
| if (maxStored == null) |
| launcherData.addJvmArg(flag + userDefined); |
| else if (userDefined == null) |
| launcherData.addJvmArg(flag + maxStored); |
| else if (AddJVMArgumentAction.compareSize(maxStored, userDefined) > 0) |
| launcherData.addJvmArg(flag + maxStored); |
| else |
| launcherData.addJvmArg(flag + userDefined); |
| } |
| } |
| |
| // Returns: 1 when a>b, 0 when a=b, -1 when a<b |
| protected static int compareSize(String a, String b) { |
| double aVal, bVal; |
| int aPower = getBytePower(a); |
| int bPower = getBytePower(b); |
| |
| aVal = getByteValue(a, aPower); |
| bVal = getByteValue(b, bPower); |
| // Ensure a value is expressed with the highest power (e.g. 2G not 2048M) |
| while (aVal > 1024) { |
| aVal /= 1024; |
| aPower += 10; |
| } |
| while (bVal > 1024) { |
| bVal /= 1024; |
| bPower += 10; |
| } |
| |
| if (aPower > bPower && aVal != 0) |
| return 1; |
| else if (aPower < bPower && bVal != 0) |
| return -1; |
| // Both have same power, so direct comparison |
| else if (aVal > bVal) |
| return 1; |
| else if (aVal < bVal) |
| return -1; |
| else |
| return 0; |
| } |
| |
| // Parse the numeric portion of an argument |
| private static double getByteValue(String arg, int power) { |
| try { |
| if (power == 0) |
| return Integer.parseInt(arg); |
| return Integer.parseInt(arg.substring(0, arg.length() - 1)); |
| } catch (NumberFormatException e) { |
| throw new IllegalArgumentException(NLS.bind(Messages.invalid_byte_format, arg)); |
| } |
| } |
| |
| private static int getBytePower(String arg) { |
| // If last digit determines if the value is in bytes, |
| // kilobytes, megabytes, or gigabytes |
| switch (arg.charAt(arg.length() - 1)) { |
| case 'k': |
| case 'K': |
| return 10; |
| case 'm': |
| case 'M': |
| return 20; |
| case 'g': |
| case 'G': |
| return 30; |
| default: |
| return 0; |
| } |
| } |
| |
| // Get the current used argument if there is one |
| protected static String getCurrentArg(String flag, String[] jvmArgs) { |
| for (int i = 0; i < jvmArgs.length; i++) |
| if (jvmArgs[i] != null && jvmArgs[i].startsWith(flag)) |
| return jvmArgs[i]; |
| return null; |
| } |
| |
| // Add one new value to those stored |
| protected static void rememberArg(Properties storedValues, String value, String flag) { |
| String argString = storedValues.getProperty(flag); |
| |
| if (argString == null) |
| argString = ""; //$NON-NLS-1$ |
| else if (argString.length() > 0) |
| argString += ','; |
| |
| argString += value; |
| |
| if (argString.length() != 0) |
| storedValues.put(flag, argString); |
| } |
| |
| protected static String[] getArgs(Properties storage, String flag) { |
| String argString = storage.getProperty(flag); |
| if (argString == null || argString.length() == 0) |
| return new String[0]; |
| |
| List<String> list = new ArrayList<>(); |
| int i = 0; |
| String arg = ""; //$NON-NLS-1$ |
| |
| // Split comma-separated list into a List |
| while (i < argString.length()) { |
| char c = argString.charAt(i++); |
| if (c == ',') { |
| list.add(arg); |
| arg = ""; //$NON-NLS-1$ |
| } else |
| arg += c; |
| } |
| |
| list.add(arg); |
| return list.toArray(new String[list.size()]); |
| } |
| |
| // Store a single user argument, null removes stored values |
| private static void setUserArg(Properties storage, String flag, String value) { |
| if (value == null) |
| storage.remove(PREFIX_USER_VALUE + flag); |
| else |
| storage.setProperty(PREFIX_USER_VALUE + flag, value); |
| } |
| |
| protected static Properties load(File storageArea) throws IOException { |
| Properties args = new Properties(); |
| File file = new File(storageArea, STORAGE); |
| if (file.exists()) { |
| // Only load if file already exists |
| FileInputStream in = null; |
| try { |
| try { |
| in = new FileInputStream(file); |
| args.load(in); |
| } finally { |
| if (in != null) |
| in.close(); |
| } |
| } catch (FileNotFoundException e) { |
| // Should not occur as we check to see if it exists |
| } |
| } |
| return args; |
| } |
| |
| protected static void save(Properties args, File storageArea) throws IOException { |
| FileOutputStream out = null; |
| File file = new File(storageArea, STORAGE); |
| if (!file.exists()) |
| // Ensure parent directory exists |
| file.getParentFile().mkdirs(); |
| |
| try { |
| try { |
| out = new FileOutputStream(file); |
| args.store(out, null); |
| } finally { |
| if (out != null) |
| out.close(); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalStateException(NLS.bind(Messages.unable_to_open_file, file)); |
| } |
| } |
| } |