blob: d04e47b763d0c4e9271e640cd7d9b55a8170417b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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.equinox.internal.frameworkadmin.equinox;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.equinox.internal.frameworkadmin.equinox.utils.FileUtils;
import org.eclipse.equinox.internal.frameworkadmin.utils.Utils;
import org.eclipse.equinox.internal.provisional.frameworkadmin.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
public class EquinoxFwConfigFileParser {
private static final String CONFIG_DIR = "@config.dir/"; //$NON-NLS-1$
private static final String KEY_ECLIPSE_PROV_CACHE = "eclipse.p2.cache"; //$NON-NLS-1$
private static final String KEY_ECLIPSE_PROV_DATA_AREA = "eclipse.p2.data.area"; //$NON-NLS-1$
private static final String KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL = "org.eclipse.equinox.simpleconfigurator.configUrl"; //$NON-NLS-1$
private static final String KEY_OSGI_BUNDLES = "osgi.bundles"; //$NON-NLS-1$
private static final String KEY_OSGI_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$
private static final String KEY_OSGI_LAUNCHER_PATH = "osgi.launcherPath"; //$NON-NLS-1$
private static final String[] PATHS = new String[] {KEY_OSGI_LAUNCHER_PATH, KEY_ECLIPSE_PROV_CACHE};
private static boolean DEBUG = false;
private static String USE_REFERENCE_STRING = null;
public EquinoxFwConfigFileParser(BundleContext context) {
if (context != null)
USE_REFERENCE_STRING = context.getProperty(EquinoxConstants.PROP_KEY_USE_REFERENCE);
}
private static String getCommandLine(BundleInfo bundleInfo, final URL baseUrl) {
String location = bundleInfo.getLocation();
if (location == null)
return null;
boolean useReference = true;
if (location.startsWith("file:")) { //$NON-NLS-1$
if (USE_REFERENCE_STRING != null && USE_REFERENCE_STRING.equals("false")) //$NON-NLS-1$
useReference = false;
}
try {
new URL(location);
} catch (MalformedURLException e) {
Log.log(LogService.LOG_ERROR, "EquinoxFwConfigFileParser.getCommandLine():bundleInfo=" + bundleInfo, e); //$NON-NLS-1$
// Never happen. ignore.
}
if (useReference)
if (!location.startsWith("reference:")) //$NON-NLS-1$
location = "reference:" + location; //$NON-NLS-1$
int startLevel = bundleInfo.getStartLevel();
boolean toBeStarted = bundleInfo.isMarkedAsStarted();
StringBuffer sb = new StringBuffer();
// if (baseUrl != null && bundleUrl.getProtocol().equals("file")) {
// String bundlePath = bundleUrl.toString();
// bundlePath = Utils.getRelativePath(bundleUrl, baseUrl);
// sb.append(bundlePath);
// } else
sb.append(location);
if (startLevel == BundleInfo.NO_LEVEL && !toBeStarted)
return sb.toString();
sb.append('@');
if (startLevel != BundleInfo.NO_LEVEL)
sb.append(startLevel);
if (toBeStarted)
sb.append(":start"); //$NON-NLS-1$
return sb.toString();
}
private static Properties getConfigProps(BundleInfo[] bInfos, ConfigData configData, LauncherData launcherData, boolean relative, File fwJar) {
Properties props = new Properties();
if (configData.getInitialBundleStartLevel() != BundleInfo.NO_LEVEL)
props.setProperty(EquinoxConstants.PROP_BUNDLES_STARTLEVEL, Integer.toString(configData.getInitialBundleStartLevel()));
if (configData.getBeginingFwStartLevel() != BundleInfo.NO_LEVEL)
props.setProperty(EquinoxConstants.PROP_INITIAL_STARTLEVEL, Integer.toString(configData.getBeginingFwStartLevel()));
final File launcher = launcherData.getLauncher();
if (launcher != null) {
String launcherName = launcher.getName();
if (launcherName.endsWith(EquinoxConstants.EXE_EXTENSION)) {
props.setProperty(EquinoxConstants.PROP_LAUNCHER_NAME, launcherName.substring(0, launcherName.lastIndexOf(EquinoxConstants.EXE_EXTENSION)));
props.setProperty(EquinoxConstants.PROP_LAUNCHER_PATH, launcher.getParentFile().getAbsolutePath());
}
}
String fwJarSt = null;
try {
if (fwJar != null) {
fwJarSt = fwJar.toURL().toExternalForm();
}
} catch (MalformedURLException e) {
// Never happens
e.printStackTrace();
}
if (bInfos != null) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bInfos.length; i++) {
normalizeLocation(bInfos[i]);
if (fwJarSt != null && fwJarSt.equals(bInfos[i].getLocation()))
continue; //framework jar should not appear in the bundles list
sb.append(getCommandLine(bInfos[i], null));
if (i + 1 < bInfos.length)
sb.append(',');
}
props.setProperty(EquinoxConstants.PROP_BUNDLES, sb.toString());
}
//TODO The following merging operations are suspicious.
props = Utils.appendProperties(props, configData.getFwIndependentProps());
props = Utils.appendProperties(props, configData.getFwDependentProps());
//Deal with the fw jar and ensure it is not set.
//TODO This can't be done before because of the previous calls to appendProperties
if (fwJarSt != null)
props.setProperty(EquinoxConstants.PROP_OSGI_FW, fwJarSt /* fwJar.getAbsolutePath() */);
else
props.remove(EquinoxConstants.PROP_OSGI_FW);
return props;
}
private static boolean getMarkedAsStartedFormat(String msg, String original) {
if (msg == null)
return false;
msg = msg.trim();
int colon = msg.indexOf(":"); //$NON-NLS-1$
if (colon > -1) {
return msg.substring(colon + 1).equals("start"); //$NON-NLS-1$
}
return msg.equals("start"); //$NON-NLS-1$
}
private static int getStartLevel(String msg, String original) {
if (msg == null)
return BundleInfo.NO_LEVEL;
msg = msg.trim();
int colon = msg.indexOf(":"); //$NON-NLS-1$
if (colon > 0) {
try {
return Integer.parseInt(msg.substring(0, colon));
} catch (NumberFormatException e) {
return BundleInfo.NO_LEVEL;
}
}
return BundleInfo.NO_LEVEL;
}
static boolean isFwDependent(String key) {
// TODO This algorithm is temporal.
if (key.startsWith(EquinoxConstants.PROP_EQUINOX_DEPENDENT_PREFIX))
return true;
return false;
}
private static void normalizeLocation(BundleInfo bInfo) {
String location = bInfo.getLocation();
try {
if (location.startsWith("file:")) { //$NON-NLS-1$
bInfo.setLocation(new URL(location).toExternalForm());
} else {
bInfo.setLocation(new File(location).toURL().toExternalForm());
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// location = location.substring("file:".length());
// if (!location.startsWith("/"))
// location = "/" + location;
// // if (fwJarSt != null)
// // if (fwJarSt.equals(location))
// // continue;
// location = Utils.replaceAll(location, File.separator, "/");
// //String jarName = location.substring(location.lastIndexOf("/") + 1);
// // if (jarName.startsWith(EquinoxConstants.FW_JAR_PLUGIN_NAME))
// // continue;
// bInfo.setLocation("file:" + location);
// }
}
/**
* @param value
*/
private static void setInstallingBundles(Manipulator manipulator, String value) throws NumberFormatException {
ConfigData configData = manipulator.getConfigData();
if (value != null) {
String[] bInfoStrings = Utils.getTokens(value, ","); //$NON-NLS-1$
for (int i = 0; i < bInfoStrings.length; i++) {
String token = bInfoStrings[i].trim();
token = FileUtils.getRealLocation(manipulator, token, false).trim();
int indexI = token.indexOf("@"); //$NON-NLS-1$
String location = (indexI == -1) ? token : token.substring(0, indexI);
String realLocation = FileUtils.getEclipseRealLocation(manipulator, location);
String slAndFlag = (indexI > -1) ? token.substring(indexI + 1) : null;
boolean markedAsStarted = getMarkedAsStartedFormat(slAndFlag, token);
int startLevel = getStartLevel(slAndFlag, token);
if (realLocation != null)
configData.addBundle(new BundleInfo(realLocation, startLevel, markedAsStarted));
else
configData.addBundle(new BundleInfo(location, null, null, startLevel, markedAsStarted));
}
}
}
/**
* inputFile must be not a directory but a file.
*
* @param manipulator
* @param inputFile
* @throws IOException
*/
public void readFwConfig(Manipulator manipulator, File inputFile) throws IOException {
if (inputFile.isDirectory())
throw new IllegalArgumentException(NLS.bind(Messages.exception_inputFileIsDirectory, inputFile));
//Initialize data structures
ConfigData configData = manipulator.getConfigData();
LauncherData launcherData = manipulator.getLauncherData();
configData.initialize();
//Load properties
Properties props = new Properties();
InputStream is = null;
try {
is = new FileInputStream(inputFile);
props.load(is);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
is = null;
}
//Start figuring out stuffs
URL rootURL = launcherData.getLauncher() != null ? launcherData.getLauncher().getParentFile().toURL() : null;
//Extracting fwkJar location needs to be done first
String launcherName = null;
String launcherPath = null;
configData.setBundles(null);
File fwJar = null;
if (props.getProperty(EquinoxConstants.PROP_OSGI_FW) != null) {
props.setProperty(KEY_OSGI_FRAMEWORK, EquinoxManipulatorImpl.makeAbsolute(props.getProperty(EquinoxConstants.PROP_OSGI_FW), getOSGiInstallArea(launcherData).toURL()));
String fwJarString = props.getProperty(KEY_OSGI_FRAMEWORK);
if (fwJarString != null) {
fwJar = new File(new URL(fwJarString).getFile());
launcherData.setFwJar(fwJar);
configData.addBundle(new BundleInfo(fwJarString));
}
}
props = makeAbsolute(props, rootURL, fwJar, inputFile.getParentFile(), getOSGiInstallArea(manipulator.getLauncherData()));
for (Enumeration enumeration = props.keys(); enumeration.hasMoreElements();) {
String key = (String) enumeration.nextElement();
String value = props.getProperty(key);
if (key.equals(EquinoxConstants.PROP_BUNDLES_STARTLEVEL))
configData.setInitialBundleStartLevel(Integer.parseInt(value));
else if (key.equals(EquinoxConstants.PROP_INITIAL_STARTLEVEL)) {
configData.setBeginningFwStartLevel(Integer.parseInt(value));
} else if (key.equals(EquinoxConstants.PROP_BUNDLES)) {
setInstallingBundles(manipulator, value);
} else {
if (isFwDependent(key)) {
configData.setFwDependentProp(key, value);
} else
configData.setFwIndependentProp(key, value);
if (key.equals(EquinoxConstants.PROP_LAUNCHER_NAME))
if (launcherData.getLauncher() == null)
launcherName = value;
if (key.equals(EquinoxConstants.PROP_LAUNCHER_PATH))
if (launcherData.getLauncher() == null)
launcherPath = value;
}
}
if (launcherName != null && launcherPath != null) {
launcherData.setLauncher(new File(launcherPath, launcherName + EquinoxConstants.EXE_EXTENSION));
}
Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_configFile, inputFile.getAbsolutePath()));
}
private static Properties makeRelative(Properties props, URL rootURL, File fwJar, File configArea, File osgiInstallArea) throws IOException {
for (int i = 0; i < PATHS.length; i++) {
String path = props.getProperty(PATHS[i]);
if (path != null)
props.put(PATHS[i], EquinoxManipulatorImpl.makeRelative(path, rootURL.getFile()));
}
if (props.getProperty(KEY_OSGI_FRAMEWORK) != null && osgiInstallArea != null) {
props.put(KEY_OSGI_FRAMEWORK, EquinoxManipulatorImpl.makeRelative(props.getProperty(KEY_OSGI_FRAMEWORK), osgiInstallArea.toURL()));
}
if (props.getProperty(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL) != null) {
props.put(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL, EquinoxManipulatorImpl.makeRelative(props.getProperty(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL), configArea.toURL()));
}
if (props.getProperty(KEY_ECLIPSE_PROV_DATA_AREA) != null) {
String url = props.getProperty(KEY_ECLIPSE_PROV_DATA_AREA);
if (url != null) {
String result = EquinoxManipulatorImpl.makeRelative(url, configArea.toURL());
//We only relativize up to the level where the p2 and config folder are siblings (e.g. foo/p2 and foo/config)
if (result.startsWith("file:../..")) //$NON-NLS-1$
result = url;
else if (!result.equals(url) && result.startsWith("file:")) //$NON-NLS-1$
result = CONFIG_DIR + result.substring(5);
props.put(KEY_ECLIPSE_PROV_DATA_AREA, result);
}
}
String value = props.getProperty(KEY_OSGI_BUNDLES);
if (value != null && fwJar != null) {
File parent = fwJar.getParentFile();
if (parent != null)
props.setProperty(KEY_OSGI_BUNDLES, EquinoxManipulatorImpl.makeArrayRelative(value, parent.toURL()));
}
return props;
}
private static Properties makeAbsolute(Properties props, URL rootURL, File fwJar, File configArea, File osgiInstallArea) throws IOException {
for (int i = 0; i < PATHS.length; i++) {
String path = props.getProperty(PATHS[i]);
if (path != null)
props.setProperty(PATHS[i], EquinoxManipulatorImpl.makeAbsolute(path, rootURL.getFile()));
}
if (props.getProperty(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL) != null) {
props.put(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL, EquinoxManipulatorImpl.makeAbsolute(props.getProperty(KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL), configArea.toURL()));
}
if (props.getProperty(KEY_ECLIPSE_PROV_DATA_AREA) != null) {
String url = props.getProperty(KEY_ECLIPSE_PROV_DATA_AREA);
if (url != null) {
if (url.startsWith(CONFIG_DIR))
url = "file:" + url.substring(CONFIG_DIR.length()); //$NON-NLS-1$
props.put(KEY_ECLIPSE_PROV_DATA_AREA, EquinoxManipulatorImpl.makeAbsolute(url, configArea.toURL()));
}
}
String value = props.getProperty(KEY_OSGI_BUNDLES);
if (value != null && fwJar != null) {
File parent = fwJar.getParentFile();
if (parent != null)
props.setProperty(KEY_OSGI_BUNDLES, EquinoxManipulatorImpl.makeArrayAbsolute(value, parent.toURL()));
}
return props;
}
public static File getOSGiInstallArea(LauncherData launcherData) {
if (launcherData == null)
return null;
String[] args = launcherData.getProgramArgs();
if (args == null)
return null;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-startup") && i + 1 < args.length && args[i + 1].charAt(1) != '-') { //$NON-NLS-1$
return fromOSGiJarToOSGiInstallArea(args[i + 1]);
}
}
if (launcherData.getFwJar() != null)
return fromOSGiJarToOSGiInstallArea(launcherData.getFwJar().getAbsolutePath());
if (launcherData.getLauncher() != null)
return launcherData.getLauncher().getParentFile();
return null;
}
private static File fromOSGiJarToOSGiInstallArea(String path) {
IPath parentFolder = new Path(path).removeLastSegments(1);
if (parentFolder.lastSegment().equals("plugins")) //$NON-NLS-1$
return parentFolder.removeLastSegments(1).toFile();
return parentFolder.toFile();
}
public void saveFwConfig(BundleInfo[] bInfos, Manipulator manipulator, boolean backup, boolean relative) throws IOException {//{
ConfigData configData = manipulator.getConfigData();
LauncherData launcherData = manipulator.getLauncherData();
File fwJar = EquinoxBundlesState.getFwJar(launcherData, configData);
launcherData.setFwJar(fwJar);
File outputFile = launcherData.getFwConfigLocation();
if (outputFile.exists()) {
if (outputFile.isFile()) {
if (!outputFile.getName().equals(EquinoxConstants.CONFIG_INI))
throw new IllegalStateException(NLS.bind(Messages.exception_fwConfigLocationName, outputFile.getAbsolutePath(), EquinoxConstants.CONFIG_INI));
} else { // Directory
outputFile = new File(outputFile, EquinoxConstants.CONFIG_INI);
}
} else {
if (!outputFile.getName().equals(EquinoxConstants.CONFIG_INI)) {
if (!outputFile.mkdir())
throw new IOException(NLS.bind(Messages.exception_failedToCreateDir, outputFile));
outputFile = new File(outputFile, EquinoxConstants.CONFIG_INI);
}
}
String header = NLS.bind(Messages.msg_ConfigFileHeader, this.getClass().getName());
Properties configProps = getConfigProps(bInfos, configData, launcherData, relative, fwJar);
if (configProps == null || configProps.size() == 0) {
Log.log(LogService.LOG_WARNING, this, "saveFwConfig() ", Messages.log_configProps); //$NON-NLS-1$
return;
}
Utils.createParentDir(outputFile);
if (DEBUG)
Utils.printoutProperties(System.out, "configProps", configProps); //$NON-NLS-1$
if (backup)
if (outputFile.exists()) {
File dest = Utils.getSimpleDataFormattedFile(outputFile);
if (!outputFile.renameTo(dest))
throw new IOException(NLS.bind(Messages.exception_failedToRename, outputFile, dest));
Log.log(LogService.LOG_INFO, this, "saveFwConfig()", NLS.bind(Messages.log_renameSuccessful, outputFile, dest)); //$NON-NLS-1$
}
FileOutputStream out = null;
try {
out = new FileOutputStream(outputFile);
configProps = makeRelative(configProps, launcherData.getLauncher().getParentFile().toURL(), fwJar, outputFile.getParentFile(), getOSGiInstallArea(manipulator.getLauncherData()));
configProps.store(out, header);
Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_fwConfigSave, outputFile));
} finally {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
}