blob: d65fcf9b6576327c7996c9d511dcc046d3fd19a6 [file] [log] [blame]
/*******************************************************************************
* 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));
}
}
}