summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPascal Rapicault (Ericsson)2013-01-27 23:41:19 (EST)
committerPascal Rapicault2013-01-28 00:08:43 (EST)
commitb86b21139a5367412cd51e86d359af33b0c03c3c (patch)
tree1bc01c47dfdcedf7ebc9888aa52002e1d9c809a2
parentc847dee6f33950f48ecd1d8eca18729f6ffc470f (diff)
downloadrt.equinox.p2-b86b21139a5367412cd51e86d359af33b0c03c3c.zip
rt.equinox.p2-b86b21139a5367412cd51e86d359af33b0c03c3c.tar.gz
rt.equinox.p2-b86b21139a5367412cd51e86d359af33b0c03c3c.tar.bz2
Squashed commit of the following:v20130128-050843
304132 - [shared] upgrading shared base causes loss of user installer plug-ins commit 8461eae803454c36f6a18013c44e37c20810d141 Merge: 23bc40c c847dee Author: Pascal Rapicault <pascal@rapicault.net> Date: Sun Jan 27 22:11:45 2013 -0500 Merge branch 'master' into prapicau/sharedInstall-part1 commit 23bc40c4f85b01f37fb0ac23992524a7c8ccd892 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Sun Jan 27 21:38:07 2013 -0500 Use constant and fix copyright header commit bc11d565b32b5b5c8bb5c93e5ea666b1d06b43ff Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Sun Jan 27 21:33:32 2013 -0500 Annotate new profile with a base profile timestamp commit ba4e7abda6e44ad47aead2fade320f9be08b27d5 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Sun Jan 27 21:32:20 2013 -0500 Add constants commit 54c8d356527d1321e25bd837e674b758aa61e248 Author: Krzysztof Daniel <kdaniel@redhat.com> Date: Thu Jan 24 13:23:15 2013 +0100 SimpleConfiguratorImpl refactoring and tests. commit 6177c466083fb7676ebfe5790bc0951043b3b727 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Thu Jan 24 11:59:45 2013 -0500 detection of change in the reconciler commit f04f46d6d283a6235367872b5eaa7e3e483509ed Merge: 5243d49 c32f111 Author: Pascal Rapicault <pascal@rapicault.net> Date: Thu Jan 24 11:43:01 2013 -0500 Merge branch 'master' into prapicau/sharedInstall-part1 commit 5243d497142b0f2631bcda8b5fed67d7ce0ddbd5 Author: Pascal Rapicault <pascal@rapicault.net> Date: Wed Jan 23 15:26:41 2013 -0500 always use shared install when the ignoreUserConfig property is set commit 12eccdad23420e7ba91f99221c852f7e32eb11de Merge: c68f394 1e9fc23 Author: Pascal Rapicault <pascal@rapicault.net> Date: Wed Jan 23 10:29:56 2013 -0500 Merge branch 'master' into prapicau/sharedInstall-part1 commit c68f394a39c4215ed7ac960495a3c59eb3cf3eee Author: Pascal Rapicault <pascal@rapicault.net> Date: Tue Jan 22 22:24:04 2013 -0500 Bug 398853 - [UI] installed IU shows as update commit aa6d632dea7ff54e9ba7c3c7f9f2ecd30afe5906 Author: Pascal Rapicault <pascal@rapicault.net> Date: Tue Jan 22 13:50:05 2013 -0500 Differentiate initial profile creation from reset. commit 4fb3429ed3fd673d5daf7ca1ce9bf1184a0afcb3 Author: Pascal Rapicault <pascal@rapicault.net> Date: Tue Jan 22 13:49:23 2013 -0500 Only show migration dialog once commit a34eac29e330a41991d003e2dcd2d8b264d77145 Author: Krzysztof Daniel <kdaniel@redhat.com> Date: Mon Jan 21 12:40:36 2013 +0100 397216: [Shared] Better shared configuration change discovery Perform dropins reindexing after master configuration had been changed. https://bugs.eclipse.org/bugs/show_bug.cgi?id=397216 commit 6981ca8bd3c1db9ab2dd9484a1f7c8950fcd1abe Merge: dfec14b 33ca260 Author: Pascal Rapicault <pascal@rapicault.net> Date: Mon Jan 21 15:04:28 2013 -0500 Merge branch 'master' into prapicau/sharedInstall-part1 commit dfec14b67a69b6fa14efb860ef8a986053a58917 Merge: 6067d05 ba5f048 Author: Pascal Rapicault <pascal@rapicault.net> Date: Mon Jan 21 11:34:38 2013 -0500 Merge branch 'master' into prapicau/sharedInstall-part1 commit ba5f048a3ac5563430104adeb173dc4f7dda6eca Author: Pascal Rapicault <pascal@rapicault.net> Date: Mon Jan 21 11:28:20 2013 -0500 Bug 398539 - Got a NPE trying to add a new update site commit 6067d05e402fe796debd9d25604cae7026df5b48 Author: Pascal Rapicault <pascal@rapicault.net> Date: Fri Jan 18 16:16:18 2013 -0500 only write timestamp file for shared install commit 8ab9410d8c797e6a8d2a97e4ba46da3d548440fa Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Fri Jan 18 13:56:46 2013 -0500 Cache the fact that the state.properties is missing commit fefbc5bdec2ce6cdb7fd71b1790bf8abdee8737a Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Fri Jan 18 13:51:54 2013 -0500 Fix bug in change detection logic commit 3de6f8593d5c1b21be3bd21000e34acb945056b1 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Wed Jan 16 19:50:32 2013 -0500 Detect changes in the bundles.info commit 446649c95063dca689f4d2c886b26975a11f3499 Author: Pascal Rapicault <pascal@rapicault.net> Date: Tue Jan 15 14:04:57 2013 -0500 Simple notification to let the user know that the base has changed. commit e004dc5270abd33a60da9a8d0340409bc8e4a38d Author: Pascal Rapicault <pascal@rapicault.net> Date: Fri Jan 11 14:15:20 2013 +0100 ignore user config.ini if out of sync with base commit a0235c0c95b9047e64d6e24c9d8f6b8588087113 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Wed Dec 12 09:57:36 2012 -0500 Obtain specific profile state properties without locking commit 1d0f129ca70716e7a181631e1ba0e71f16e35e08 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Mon Dec 10 16:06:38 2012 -0500 Remember the timestamp of the base config.ini commit 3134caecfd244fd88386f3ce4bd1a6fc71fe8007 Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Wed Dec 5 16:21:50 2012 -0500 Support to ignore the existing profile if the base has changed commit 7f0ba4e643f40bc0143617b93b2238388d38216d Author: Pascal Rapicault (Ericsson) <pascal.rapicault@ericsson.com> Date: Tue Dec 4 11:23:37 2012 -0500 Remove externalization warning
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/EquinoxFwConfigFileParser.java97
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/Messages.java2
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/messages.properties2
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/config.ini1
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/user-config.ini3
-rw-r--r--bundles/org.eclipse.equinox.frameworkadmin.test/src/org/eclipse/equinox/frameworkadmin/tests/SharedConfigurationTest.java126
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/SimpleProfileRegistry.java144
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfile.java24
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfileRegistry.java5
-rw-r--r--bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/Activator.java7
-rw-r--r--bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java14
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTest.java106
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTests.java1
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/master/bundles.info0
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/user/bundles.info0
-rw-r--r--bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java44
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/p2/ui/RepositoryManipulationPage.java5
-rw-r--r--bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java95
-rw-r--r--bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/SimpleConfiguratorImpl.java103
19 files changed, 667 insertions, 112 deletions
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/EquinoxFwConfigFileParser.java b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/EquinoxFwConfigFileParser.java
index 7f19233..3f7e4ff 100644
--- a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/EquinoxFwConfigFileParser.java
+++ b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/EquinoxFwConfigFileParser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2011 IBM Corporation and others.
+ * Copyright (c) 2007, 2013 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
@@ -7,6 +7,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB (Pascal Rapicault) - Bug 397216 -[Shared] Better shared
+ * configuration change discovery
*******************************************************************************/
package org.eclipse.equinox.internal.frameworkadmin.equinox;
@@ -30,6 +32,9 @@ public class EquinoxFwConfigFileParser {
private static final String KEY_ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_CONFIGURL = "org.eclipse.equinox.simpleconfigurator.configUrl"; //$NON-NLS-1$
private static final String REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$
private static final String FILE_PROTOCOL = "file:"; //$NON-NLS-1$
+ private static final String BASE_TIMESTAMP_FILE_CONFIGINI = ".baseConfigIniTimestamp"; //$NON-NLS-1$
+ private static final String KEY_CONFIGINI_TIMESTAMP = "configIniTimestamp"; //$NON-NLS-1$
+
private static boolean DEBUG = false;
public EquinoxFwConfigFileParser(BundleContext context) {
@@ -198,6 +203,7 @@ public class EquinoxFwConfigFileParser {
if (inputFile.isDirectory())
throw new IllegalArgumentException(NLS.bind(Messages.exception_inputFileIsDirectory, inputFile));
+ boolean baseHasChanged = false;
//Initialize data structures
ConfigData configData = manipulator.getConfigData();
LauncherData launcherData = manipulator.getLauncherData();
@@ -208,9 +214,15 @@ public class EquinoxFwConfigFileParser {
Properties props = loadProperties(inputFile);
// load shared configuration properties
- Properties sharedConfigProperties = getSharedConfiguration(props.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA), ParserUtils.getOSGiInstallArea(Arrays.asList(manipulator.getLauncherData().getProgramArgs()), props, manipulator.getLauncherData()));
+ Properties sharedConfigProperties = getSharedConfiguration(ParserUtils.getOSGiInstallArea(Arrays.asList(manipulator.getLauncherData().getProgramArgs()), props, manipulator.getLauncherData()), props.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA));
if (sharedConfigProperties != null) {
- sharedConfigProperties.putAll(props);
+ baseHasChanged = hasBaseChanged(inputFile, manipulator, props);
+ if (!baseHasChanged)
+ sharedConfigProperties.putAll(props);
+ else {
+ sharedConfigProperties.put(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA, props.get(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA));
+ }
+
props = sharedConfigProperties;
}
@@ -222,7 +234,9 @@ public class EquinoxFwConfigFileParser {
//readLauncherPath(props, rootURI);
readp2DataArea(props, configArea);
readSimpleConfiguratorURL(props, configArea);
- readBundlesList(manipulator, ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), props, launcherData).toURI(), props);
+
+ if (!baseHasChanged)
+ readBundlesList(manipulator, ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), props, launcherData).toURI(), props);
readInitialStartLeve(configData, props);
readDefaultStartLevel(configData, props);
@@ -236,6 +250,21 @@ public class EquinoxFwConfigFileParser {
Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_configFile, inputFile.getAbsolutePath()));
}
+ private boolean hasBaseChanged(File configIni, Manipulator manipulator, Properties configProps) {
+ LauncherData launcherData = manipulator.getLauncherData();
+ File sharedConfigIni = findSharedConfigIniFile(ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), configProps, launcherData), configProps.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA));
+ File timestampFile = new File(configIni.getParentFile(), BASE_TIMESTAMP_FILE_CONFIGINI);
+ Properties timestamps;
+ try {
+ timestamps = loadProperties(timestampFile);
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ return !String.valueOf(sharedConfigIni.lastModified()).equals(timestamps.getProperty(KEY_CONFIGINI_TIMESTAMP));
+ }
+
private void readDefaultStartLevel(ConfigData configData, Properties props) {
if (props.getProperty(EquinoxConstants.PROP_BUNDLES_STARTLEVEL) != null)
configData.setInitialBundleStartLevel(Integer.parseInt(props.getProperty(EquinoxConstants.PROP_BUNDLES_STARTLEVEL)));
@@ -293,7 +322,8 @@ public class EquinoxFwConfigFileParser {
props.load(is);
} finally {
try {
- is.close();
+ if (is != null)
+ is.close();
} catch (IOException e) {
Log.log(LogService.LOG_WARNING, NLS.bind(Messages.log_failed_reading_properties, inputFile));
}
@@ -302,7 +332,18 @@ public class EquinoxFwConfigFileParser {
return props;
}
- private File findSharedConfigIniFile(URL rootURL, String sharedConfigurationArea) {
+ private File findSharedConfigIniFile(File base, String sharedConfigurationArea) {
+ if (base == null)
+ return null;
+ URL rootURL;
+ try {
+ rootURL = base.toURL();
+ } catch (MalformedURLException e1) {
+ return null;
+ }
+ if (rootURL == null)
+ return null;
+
URL sharedConfigurationURL = null;
try {
sharedConfigurationURL = new URL(sharedConfigurationArea);
@@ -415,7 +456,6 @@ public class EquinoxFwConfigFileParser {
outputFile = new File(outputFile, EquinoxConstants.CONFIG_INI);
}
}
- String header = "This configuration file was written by: " + this.getClass().getName(); //$NON-NLS-1$
Properties configProps = new Properties();
//URI rootURI = launcherData.getLauncher() != null ? launcherData.getLauncher().getParentFile().toURI() : null;
@@ -459,13 +499,18 @@ public class EquinoxFwConfigFileParser {
Log.log(LogService.LOG_INFO, this, "saveFwConfig()", NLS.bind(Messages.log_renameSuccessful, outputFile, dest)); //$NON-NLS-1$
}
+ filterPropertiesFromSharedArea(configProps, manipulator);
+ saveProperties(outputFile, configProps);
+ rememberSharedConfigurationTimestamp(configProps, manipulator, outputFile.getParentFile());
+ }
+
+ private void saveProperties(File outputFile, Properties configProps) throws IOException {
+ String header = "This configuration file was written by: " + this.getClass().getName(); //$NON-NLS-1$
FileOutputStream out = null;
try {
out = new FileOutputStream(outputFile);
- // configProps = makeRelative(configProps, launcherData.getLauncher().getParentFile().toURI(), fwJar, outputFile.getParentFile(), getOSGiInstallArea(manipulator.getLauncherData()));
- filterPropertiesFromSharedArea(configProps, manipulator);
configProps.store(out, header);
- Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_fwConfigSave, outputFile));
+ Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_propertiesSaved, outputFile));
} finally {
try {
out.flush();
@@ -473,14 +518,13 @@ public class EquinoxFwConfigFileParser {
} catch (IOException e) {
e.printStackTrace();
}
- out = null;
}
}
private void filterPropertiesFromSharedArea(Properties configProps, Manipulator manipulator) {
LauncherData launcherData = manipulator.getLauncherData();
//Remove from the config file that we are about to write the properties that are unchanged compared to what is in the base
- Properties sharedConfigProperties = getSharedConfiguration(configProps.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA), ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), configProps, launcherData));
+ Properties sharedConfigProperties = getSharedConfiguration(ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), configProps, launcherData), configProps.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA));
if (sharedConfigProperties == null)
return;
Enumeration keys = configProps.propertyNames();
@@ -549,16 +593,28 @@ public class EquinoxFwConfigFileParser {
}
}
- private Properties getSharedConfiguration(String sharedConfigurationArea, File baseFile) {
- if (sharedConfigurationArea == null)
- return null;
- File sharedConfigIni;
+ private void rememberSharedConfigurationTimestamp(Properties configProps, Manipulator manipulator, File folder) throws IOException {
+ LauncherData launcherData = manipulator.getLauncherData();
+ //Remove from the config file that we are about to write the properties that are unchanged compared to what is in the base
+ File sharedConfigIni = findSharedConfigIniFile(ParserUtils.getOSGiInstallArea(Arrays.asList(launcherData.getProgramArgs()), configProps, launcherData), configProps.getProperty(EquinoxConstants.PROP_SHARED_CONFIGURATION_AREA));
+ if (sharedConfigIni == null)
+ return;
+ File timestampFile = new File(folder, BASE_TIMESTAMP_FILE_CONFIGINI);
+ Properties timestamps;
try {
- sharedConfigIni = findSharedConfigIniFile(baseFile.toURL(), sharedConfigurationArea);
- } catch (MalformedURLException e) {
- return null;
+ timestamps = loadProperties(timestampFile);
+ } catch (IOException e) {
+ timestamps = new Properties();
}
- if (sharedConfigIni != null && sharedConfigIni.exists())
+ timestamps.setProperty(KEY_CONFIGINI_TIMESTAMP, String.valueOf(sharedConfigIni.lastModified()));
+ saveProperties(timestampFile, timestamps);
+ }
+
+ private Properties getSharedConfiguration(File baseFile, String sharedConfigurationArea) {
+ if (sharedConfigurationArea == null)
+ return null;
+ File sharedConfigIni = findSharedConfigIniFile(baseFile, sharedConfigurationArea);
+ if (sharedConfigIni != null && sharedConfigIni.exists()) {
try {
return loadProperties(sharedConfigIni);
} catch (FileNotFoundException e) {
@@ -566,6 +622,7 @@ public class EquinoxFwConfigFileParser {
} catch (IOException e) {
return null;
}
+ }
return null;
}
}
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/Messages.java b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/Messages.java
index 2453f7b..66920c2 100644
--- a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/Messages.java
+++ b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/Messages.java
@@ -31,7 +31,7 @@ public class Messages extends NLS {
public static String log_configFile;
public static String log_configProps;
public static String log_renameSuccessful;
- public static String log_fwConfigSave;
+ public static String log_propertiesSaved;
public static String log_launcherConfigSave;
public static String log_shared_config_url;
public static String log_shared_config_relative_url;
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/messages.properties b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/messages.properties
index a5d0d50..3c84f4d 100644
--- a/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/messages.properties
+++ b/bundles/org.eclipse.equinox.frameworkadmin.equinox/src/org/eclipse/equinox/internal/frameworkadmin/equinox/messages.properties
@@ -26,7 +26,7 @@ exception_errorReadingFile = An error occured while reading {0}.
log_configFile= Configuration file ({0}) has been read successfully.
log_configProps= Configuration properties is empty.
log_renameSuccessful= Successfully renamed {0} to {1}.
-log_fwConfigSave= Framework Configuration was saved successfully in {0}.
+log_propertiesSaved= File {0} was saved successfully.
log_launcherConfigSave= Launcher Configuration was saved successfully in {0}.
log_shared_config_url=Failed creating shared configuration url for {0}.
log_shared_config_relative_url=Failed creating shared configuration url for root: {0} and sharedConfiguration: {1}.
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/config.ini b/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/config.ini
new file mode 100644
index 0000000..cb5fd86
--- /dev/null
+++ b/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/config.ini
@@ -0,0 +1 @@
+sharedKey=sharedValue \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/user-config.ini b/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/user-config.ini
new file mode 100644
index 0000000..8797ba5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.frameworkadmin.test/dataFile/sharedconfiguration/ignoreUserConfig/user-config.ini
@@ -0,0 +1,3 @@
+osgi.sharedConfiguration.area=file\:configuration/
+userKey=userValue
+
diff --git a/bundles/org.eclipse.equinox.frameworkadmin.test/src/org/eclipse/equinox/frameworkadmin/tests/SharedConfigurationTest.java b/bundles/org.eclipse.equinox.frameworkadmin.test/src/org/eclipse/equinox/frameworkadmin/tests/SharedConfigurationTest.java
index 134d7be..0d0eba5 100644
--- a/bundles/org.eclipse.equinox.frameworkadmin.test/src/org/eclipse/equinox/frameworkadmin/tests/SharedConfigurationTest.java
+++ b/bundles/org.eclipse.equinox.frameworkadmin.test/src/org/eclipse/equinox/frameworkadmin/tests/SharedConfigurationTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2010 IBM Corporation and others.
+ * Copyright (c) 2008, 2013 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
@@ -7,20 +7,29 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB (Pascal Rapicault) - Improve shared install
*******************************************************************************/
package org.eclipse.equinox.frameworkadmin.tests;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.net.URISyntaxException;
+import java.util.Properties;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.equinox.frameworkadmin.BundleInfo;
+import org.eclipse.equinox.internal.frameworkadmin.equinox.Log;
+import org.eclipse.equinox.internal.frameworkadmin.equinox.Messages;
import org.eclipse.equinox.internal.provisional.frameworkadmin.*;
+import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleException;
+import org.osgi.service.log.LogService;
public class SharedConfigurationTest extends AbstractFwkAdminTest {
public SharedConfigurationTest(String name) {
super(name);
}
-
+
public void testDefaultConfiguration() throws IllegalStateException, FrameworkAdminRuntimeException, IOException, BundleException {
startSimpleConfiguratorManipulator();
FrameworkAdmin fwkAdmin = getEquinoxFrameworkAdmin();
@@ -30,19 +39,19 @@ public class SharedConfigurationTest extends AbstractFwkAdminTest {
File defaultConfigurationFolder = new File(installFolder, "configuration");
defaultConfigurationFolder.mkdirs();
copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/config.ini"), new File(defaultConfigurationFolder, "config.ini"));
-
+
String launcherName = "foo";
LauncherData launcherData = manipulator.getLauncherData();
launcherData.setFwConfigLocation(defaultConfigurationFolder);
launcherData.setLauncher(new File(installFolder, launcherName));
-
+
try {
manipulator.load();
} catch (IllegalStateException e) {
//TODO We ignore the framework JAR location not set exception
}
-
+
assertEquals("false", manipulator.getConfigData().getProperty("config.shared"));
assertEquals("true", manipulator.getConfigData().getProperty("from.parent"));
}
@@ -59,23 +68,23 @@ public class SharedConfigurationTest extends AbstractFwkAdminTest {
File userConfigurationFolder = new File(installFolder, "user/configuration");
userConfigurationFolder.mkdirs();
copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/user-config.ini"), new File(userConfigurationFolder, "config.ini"));
-
+
String launcherName = "foo";
LauncherData launcherData = manipulator.getLauncherData();
launcherData.setFwConfigLocation(userConfigurationFolder);
launcherData.setLauncher(new File(installFolder, launcherName));
-
+
try {
manipulator.load();
} catch (IllegalStateException e) {
//TODO We ignore the framework JAR location not set exception
}
-
+
assertEquals("true", manipulator.getConfigData().getProperty("config.shared"));
assertEquals("true", manipulator.getConfigData().getProperty("from.parent"));
}
-
+
public void testNotSharedConfiguration() throws IllegalStateException, FrameworkAdminRuntimeException, IOException, BundleException {
startSimpleConfiguratorManipulator();
FrameworkAdmin fwkAdmin = getEquinoxFrameworkAdmin();
@@ -88,20 +97,109 @@ public class SharedConfigurationTest extends AbstractFwkAdminTest {
File userConfigurationFolder = new File(installFolder, "user/configuration");
userConfigurationFolder.mkdirs();
copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/user-noshare-config.ini"), new File(userConfigurationFolder, "config.ini"));
-
+
String launcherName = "foo";
LauncherData launcherData = manipulator.getLauncherData();
launcherData.setFwConfigLocation(userConfigurationFolder);
launcherData.setLauncher(new File(installFolder, launcherName));
-
+
try {
manipulator.load();
} catch (IllegalStateException e) {
//TODO We ignore the framework JAR location not set exception
}
-
+
assertEquals("false", manipulator.getConfigData().getProperty("config.shared"));
assertEquals(null, manipulator.getConfigData().getProperty("from.parent"));
}
+
+ public void testConfigIniTimestamp() throws BundleException, FrameworkAdminRuntimeException, IOException, URISyntaxException {
+ startSimpleConfiguratorManipulator();
+ FrameworkAdmin fwkAdmin = getEquinoxFrameworkAdmin();
+ Manipulator manipulator = fwkAdmin.getManipulator();
+
+ File installFolder = Activator.getContext().getDataFile(SharedConfigurationTest.class.getName());
+ File defaultConfigurationFolder = new File(installFolder, "configuration");
+ defaultConfigurationFolder.mkdirs();
+ copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/config.ini"), new File(defaultConfigurationFolder, "config.ini"));
+ File userConfigurationFolder = new File(installFolder, "user/configuration");
+ userConfigurationFolder.mkdirs();
+ copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/user-config.ini"), new File(userConfigurationFolder, "config.ini"));
+
+ String launcherName = "foo";
+
+ LauncherData launcherData = manipulator.getLauncherData();
+ launcherData.setFwConfigLocation(userConfigurationFolder);
+ launcherData.setLauncher(new File(installFolder, launcherName));
+
+ try {
+ manipulator.load();
+ } catch (IllegalStateException e) {
+ //TODO We ignore the framework JAR location not set exception
+ }
+
+ BundleInfo osgiBi = new BundleInfo("org.eclipse.osgi", "3.3.1", URIUtil.toURI(FileLocator.resolve(Activator.getContext().getBundle().getEntry("dataFile/org.eclipse.osgi.jar"))), 0, true);
+ BundleInfo configuratorBi = new BundleInfo("org.eclipse.equinox.simpleconfigurator", "1.0.0", URIUtil.toURI(FileLocator.resolve(Activator.getContext().getBundle().getEntry("dataFile/org.eclipse.equinox.simpleconfigurator.jar"))), 1, true);
+
+ manipulator.getConfigData().addBundle(osgiBi);
+ manipulator.getConfigData().addBundle(configuratorBi);
+
+ manipulator.save(false);
+ File baseTimestamp = new File(userConfigurationFolder, ".baseTimestamps");
+ assertIsFile(baseTimestamp);
+ assertContent(baseTimestamp, Long.toString(new File(defaultConfigurationFolder, "config.ini").lastModified()));
+ }
+
+ public void testConfigurationIgnoredWhenChanged() throws BundleException, FrameworkAdminRuntimeException, IOException {
+ startSimpleConfiguratorManipulator();
+ FrameworkAdmin fwkAdmin = getEquinoxFrameworkAdmin();
+ Manipulator manipulator = fwkAdmin.getManipulator();
+
+ //setup the files
+ File installFolder = Activator.getContext().getDataFile(SharedConfigurationTest.class.getName());
+ File defaultConfigurationFolder = new File(installFolder, "configuration");
+ defaultConfigurationFolder.mkdirs();
+ copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/ignoreUserConfig/config.ini"), new File(defaultConfigurationFolder, "config.ini"));
+ File userConfigurationFolder = new File(installFolder, "user/configuration");
+ userConfigurationFolder.mkdirs();
+ copy("creating shared config.ini", getTestData("", "dataFile/sharedconfiguration/ignoreUserConfig/user-config.ini"), new File(userConfigurationFolder, "config.ini"));
+
+ //setup the timestamp
+ Properties p = new Properties();
+ p.setProperty("configIniTimestamp", Long.toString(new File(defaultConfigurationFolder, "config.ini").lastModified()));
+ saveProperties(new File(userConfigurationFolder, ".baseTimestamps"), p);
+
+ String launcherName = "foo";
+
+ LauncherData launcherData = manipulator.getLauncherData();
+ launcherData.setFwConfigLocation(userConfigurationFolder);
+ launcherData.setLauncher(new File(installFolder, launcherName));
+
+ try {
+ manipulator.load();
+ } catch (IllegalStateException e) {
+ //TODO We ignore the framework JAR location not set exception
+ }
+
+ assertNull(manipulator.getConfigData().getProperty("userKey"));
+ assertEquals("sharedValue", manipulator.getConfigData().getProperty("sharedKey"));
+ }
+
+ private void saveProperties(File outputFile, Properties configProps) throws IOException {
+ String header = "This configuration file was written by: " + this.getClass().getName(); //$NON-NLS-1$
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(outputFile);
+ configProps.store(out, header);
+ Log.log(LogService.LOG_INFO, NLS.bind(Messages.log_propertiesSaved, outputFile));
+ } finally {
+ try {
+ out.flush();
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/SimpleProfileRegistry.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/SimpleProfileRegistry.java
index 945ec04..9e02654 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/SimpleProfileRegistry.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/SimpleProfileRegistry.java
@@ -1,12 +1,12 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 IBM Corporation and others. All rights reserved. This
+ * Copyright (c) 2007, 2013 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
- * Ericsson AB (Pascal Rapicault) - reading preferences from base in shared install
+ * Ericsson AB - ongoing development
******************************************************************************/
package org.eclipse.equinox.internal.p2.engine;
@@ -38,6 +38,8 @@ import org.xml.sax.SAXException;
public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
+ private static final String SIMPLE_PROFILE_REGISTRY_INTERNAL = "_simpleProfileRegistry_internal_";
+ private static final String ECLIPSE_IGNORE_USER_CONFIGURATION = "eclipse.ignoreUserConfiguration"; //$NON-NLS-1$
private static final String PROFILE_REGISTRY = "profile registry"; //$NON-NLS-1$
private static final String PROFILE_PROPERTIES_FILE = "state.properties"; //$NON-NLS-1$
@@ -168,7 +170,7 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
}
public synchronized String toString() {
- return "Profile registry for location: " + store.getAbsolutePath() + "\n" + getProfileMap().toString(); //$NON-NLS-1$
+ return "Profile registry for location: " + store.getAbsolutePath() + "\n" + getProfileMap().toString(); //$NON-NLS-1$ //$NON-NLS-2$
}
public synchronized IProfile getProfile(String id) {
@@ -243,12 +245,57 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
if (SELF.equals(id))
id = self;
Profile profile = getProfileMap().get(id);
- if (profile == null && self != null && self.equals(id))
- profile = createSurrogateProfile(id);
-
+ if (self != null && self.equals(id)) {
+ boolean resetProfile = false;
+ if (profile != null && ignoreExistingProfile(profile)) {
+ internalSetProfileStateProperty(profile, profile.getTimestamp(), IProfile.STATE_PROP_SHARED_INSTALL, IProfile.STATE_SHARED_INSTALL_VALUE_BEFOREFLUSH);
+ profile = null;
+ resetProfile = true;
+ }
+ if (profile == null) {
+ profile = createSurrogateProfile(id);
+ if (resetProfile) {
+ //Now that we created a new profile. Tag it, override the property and register the timestamp in the agent registry for pickup by other
+ internalSetProfileStateProperty(profile, profile.getTimestamp(), IProfile.STATE_PROP_SHARED_INSTALL, IProfile.STATE_SHARED_INSTALL_VALUE_NEW);
+ internalSetProfileStateProperty(profile, profile.getTimestamp(), SIMPLE_PROFILE_REGISTRY_INTERNAL + getBaseTimestamp(profile.getProfileId()), getBaseTimestamp(id));
+ System.setProperty(ECLIPSE_IGNORE_USER_CONFIGURATION, "profileFlushed"); //$NON-NLS-1$
+ agent.registerService(SERVICE_SHARED_INSTALL_NEW_TIMESTAMP, Long.toString(profile.getTimestamp()));
+ } else {
+ //This is the first time we create the shared profile. Tag it as such and also remember the timestamp of the base
+ internalSetProfileStateProperty(profile, profile.getTimestamp(), IProfile.STATE_PROP_SHARED_INSTALL, IProfile.STATE_SHARED_INSTALL_VALUE_INITIAL);
+ internalSetProfileStateProperty(profile, profile.getTimestamp(), SIMPLE_PROFILE_REGISTRY_INTERNAL + getBaseTimestamp(profile.getProfileId()), getBaseTimestamp(id));
+ }
+ }
+ }
return profile;
}
+ private boolean ignoreExistingProfile(IProfile profile) {
+ if (!Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(ECLIPSE_IGNORE_USER_CONFIGURATION)))
+ return false;
+
+ String baseTimestamp = getBaseTimestamp(profile.getProfileId());
+ if (baseTimestamp == null)
+ return false;
+
+ if (internalGetProfileStateProperties(profile, SIMPLE_PROFILE_REGISTRY_INTERNAL + baseTimestamp, false).size() != 0)
+ return false;
+
+ return true;
+ }
+
+ private String getBaseTimestamp(String id) {
+ IProvisioningAgent installer = (IProvisioningAgent) agent.getService(IProvisioningAgent.SHARED_BASE_AGENT);
+ if (installer == null)
+ return null;
+ IProfileRegistry registry = (IProfileRegistry) installer.getService(IProfileRegistry.SERVICE_NAME);
+ long[] revisions = registry.listProfileTimestamps(id);
+ if (revisions.length >= 1) {
+ return Long.toString(revisions[revisions.length - 1]);
+ }
+ return null;
+ }
+
private Profile createSurrogateProfile(String id) {
if (surrogateProfileHandler == null)
return null;
@@ -294,7 +341,7 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
public synchronized void updateProfile(Profile profile) {
String id = profile.getProfileId();
- Profile current = internalGetProfile(id);
+ Profile current = getProfileMap().get(id);
if (current == null)
throw new IllegalArgumentException(NLS.bind(Messages.profile_does_not_exist, id));
@@ -730,7 +777,7 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
}
public synchronized boolean isCurrent(IProfile profile) {
- Profile internalProfile = internalGetProfile(profile.getProfileId());
+ Profile internalProfile = getProfileMap().get(profile.getProfileId());
if (internalProfile == null)
throw new IllegalArgumentException(NLS.bind(Messages.profile_not_registered, profile.getProfileId()));
@@ -833,10 +880,9 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
}
public synchronized void unlockProfile(IProfile profile) {
- Profile internalProfile = internalGetProfile(profile.getProfileId());
- if (internalProfile == null)
+ if (profile == null)
throw new IllegalArgumentException(NLS.bind(Messages.profile_not_registered, profile.getProfileId()));
- internalUnlockProfile(internalProfile);
+ internalUnlockProfile(profile);
}
private void internalUnlockProfile(IProfile profile) {
@@ -897,6 +943,8 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
// return true if the cached timestamp is the same as the one on disk
boolean isCurrent() {
+ if (!file.exists())
+ return true;
return file.lastModified() == timestamp;
}
@@ -936,8 +984,10 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
File file = new File(profileDirectory, PROFILE_PROPERTIES_FILE);
Properties properties = new Properties();
- if (!file.exists())
+ if (!file.exists()) {
+ lastAccessedProperties = new ProfileStateProperties(id, file, properties);
return properties;
+ }
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
@@ -1032,22 +1082,30 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
public IStatus setProfileStateProperties(String id, long timestamp, Map<String, String> propertiesToAdd) {
if (id == null || propertiesToAdd == null)
throw new NullPointerException();
- IStatus result = validateState(id, timestamp);
+
+ Profile internalProfile = internalGetProfile(id);
+ return internalSetProfileStateProperties(internalProfile, timestamp, propertiesToAdd);
+ }
+
+ private IStatus internalSetProfileStateProperties(IProfile profile, long timestamp, Map<String, String> propertiesToAdd) {
+ IStatus result = validateState(profile.getProfileId(), timestamp);
if (!result.isOK())
return result;
- Profile internalProfile = internalGetProfile(id);
- lockProfile(internalProfile);
+
+ if (!internalLockProfile(profile))
+ throw new IllegalStateException(Messages.SimpleProfileRegistry_Profile_in_use);
+
try {
- Properties properties = readStateProperties(id);
+ Properties properties = readStateProperties(profile.getProfileId());
for (Map.Entry<String, String> entry : propertiesToAdd.entrySet()) {
// property key format is timestamp.key
properties.put(timestamp + "." + entry.getKey(), entry.getValue()); //$NON-NLS-1$
}
- writeStateProperties(id, properties);
+ writeStateProperties(profile.getProfileId(), properties);
} catch (ProvisionException e) {
return e.getStatus();
} finally {
- unlockProfile(internalProfile);
+ internalUnlockProfile(profile);
}
return Status.OK_STATUS;
}
@@ -1056,27 +1114,36 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
* @see org.eclipse.equinox.p2.engine.IProfileRegistry#setProfileStateProperty(java.lang.String, long, java.lang.String, java.lang.String)
*/
public IStatus setProfileStateProperty(String id, long timestamp, String key, String value) {
- if (id == null || key == null || value == null)
+ if (id == null)
+ throw new NullPointerException();
+ return internalSetProfileStateProperty(internalGetProfile(id), timestamp, key, value);
+ }
+
+ private IStatus internalSetProfileStateProperty(IProfile profile, long timestamp, String key, String value) {
+ if (key == null || value == null)
throw new NullPointerException();
Map<String, String> properties = new HashMap<String, String>();
properties.put(key, value);
- return setProfileStateProperties(id, timestamp, properties);
+
+ return internalSetProfileStateProperties(profile, timestamp, properties);
}
- /* (non-Javadoc)
- * @see org.eclipse.equinox.p2.engine.IProfileRegistry#getProfileStateProperties(java.lang.String, long)
- */
public Map<String, String> getProfileStateProperties(String id, long timestamp) {
if (id == null)
throw new NullPointerException();
+ return internalGetProfileStateProperties(internalGetProfile(id), timestamp, true);
+ }
+ private Map<String, String> internalGetProfileStateProperties(IProfile profile, long timestamp, boolean lock) {
Map<String, String> result = new HashMap<String, String>();
String timestampString = String.valueOf(timestamp);
int keyOffset = timestampString.length() + 1;
- Profile internalProfile = internalGetProfile(id);
- lockProfile(internalProfile);
+ lock = lock || lastAccessedProperties == null;
+ if (lock)
+ if (!internalLockProfile(profile))
+ throw new IllegalStateException(Messages.SimpleProfileRegistry_Profile_in_use);
try {
- Properties properties = readStateProperties(id);
+ Properties properties = readStateProperties(profile.getProfileId());
Iterator<Object> keys = properties.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
@@ -1086,7 +1153,8 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
} catch (ProvisionException e) {
LogHelper.log(e);
} finally {
- unlockProfile(internalProfile);
+ if (lock)
+ internalUnlockProfile(profile);
}
return result;
}
@@ -1098,11 +1166,18 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
if (id == null || userKey == null)
throw new NullPointerException();
- Map<String, String> result = new HashMap<String, String>();
Profile internalProfile = internalGetProfile(id);
- lockProfile(internalProfile);
+ return internalGetProfileStateProperties(internalProfile, userKey, true);
+ }
+
+ private Map<String, String> internalGetProfileStateProperties(IProfile profile, String userKey, boolean lock) {
+ Map<String, String> result = new HashMap<String, String>();
+ lock = lock || lastAccessedProperties == null;
+ if (lock)
+ if (!internalLockProfile(profile))
+ throw new IllegalStateException(Messages.SimpleProfileRegistry_Profile_in_use);
try {
- Properties properties = readStateProperties(id);
+ Properties properties = readStateProperties(profile.getProfileId());
Iterator<Object> keys = properties.keySet().iterator();
while (keys.hasNext()) {
// property key format is timestamp.key
@@ -1115,7 +1190,8 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
} catch (ProvisionException e) {
LogHelper.log(e);
} finally {
- unlockProfile(internalProfile);
+ if (lock)
+ internalUnlockProfile(profile);
}
return result;
}
@@ -1131,7 +1207,9 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
return Status.OK_STATUS;
Profile internalProfile = internalGetProfile(id);
- lockProfile(internalProfile);
+ if (!internalLockProfile(internalProfile))
+ throw new IllegalStateException(Messages.SimpleProfileRegistry_Profile_in_use);
+
try {
Properties properties = readStateProperties(id);
String timestampString = String.valueOf(timestamp);
@@ -1154,7 +1232,7 @@ public class SimpleProfileRegistry implements IProfileRegistry, IAgentService {
} catch (ProvisionException e) {
return e.getStatus();
} finally {
- unlockProfile(internalProfile);
+ internalUnlockProfile(internalProfile);
}
return Status.OK_STATUS;
}
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfile.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfile.java
index 1f8de76..7bd0060 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfile.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfile.java
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB - ongoing development
*******************************************************************************/
package org.eclipse.equinox.p2.engine;
@@ -146,6 +147,29 @@ public interface IProfile extends IQueryable<IInstallableUnit> {
public static final String STATE_PROP_TAG = "org.eclipse.equinox.p2.state.tag"; //$NON-NLS-1$
/**
+ * Profile state metadata property key used to represent the state of the user profile when running in shared install.
+ * The value for this property could be: {@value #STATE_PROP_INITIAL}, {@value #STATE_SHARED_INSTALL_VALUE_BEFOREFLUSH}, or {@value #STATE_SHARED_INSTALL_VALUE_NEW}
+ * @since 2.3
+ */
+ public static final String STATE_PROP_SHARED_INSTALL = "org.eclipse.equinox.p2.state.shared"; //$NON-NLS-1$
+
+ /**
+ * Value to represent a user profile the first time it is created.
+ * @since 2.3
+ */
+ public static final String STATE_SHARED_INSTALL_VALUE_INITIAL = "initial"; //$NON-NLS-1$
+ /**
+ * Value to represent a user profile before it is being flushed because the base had changed.
+ * @since 2.3
+ */
+ public static final String STATE_SHARED_INSTALL_VALUE_BEFOREFLUSH = "beforeFlush"; //$NON-NLS-1$
+ /**
+ * Value to represent the new user profile created once the base profile has been flushed.
+ * @since 2.3
+ */
+ public static final String STATE_SHARED_INSTALL_VALUE_NEW = "new"; //$NON-NLS-1$
+
+ /**
* Profile property constant for additional parameters of the downloading stats(e.g., package=jee&os=linux).
* @since 2.2
*/
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfileRegistry.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfileRegistry.java
index 381a61e..b2490c8 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfileRegistry.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/p2/engine/IProfileRegistry.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2011 IBM Corporation and others.
+ * Copyright (c) 2007, 2013 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB - ongoing development
*******************************************************************************/
package org.eclipse.equinox.p2.engine;
@@ -37,6 +38,8 @@ public interface IProfileRegistry {
*/
public static final String SERVICE_NAME = IProfileRegistry.class.getName();
+ public static final String SERVICE_SHARED_INSTALL_NEW_TIMESTAMP = IProfileRegistry.class.getName() + '_' + "NEW_SELF_TIMESTAMP"; //$NON-NLS-1$
+
/**
* Return the profile in the registry that has the given id. If it does not exist,
* then return <code>null</code>.
diff --git a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/Activator.java b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/Activator.java
index d8da4f5..8008719 100644
--- a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/Activator.java
+++ b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/Activator.java
@@ -227,6 +227,13 @@ public class Activator implements BundleActivator {
trace("Performing reconciliation."); //$NON-NLS-1$
return false;
}
+ // master configuration changed. Reconcile.
+ if (Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(ProfileSynchronizer.PROP_IGNORE_USER_CONFIGURATION))) {
+ Activator.trace("Master profile changed."); //$NON-NLS-1$
+ Activator.trace("Performing reconciliation."); //$NON-NLS-1$
+ return false;
+ }
+
// read timestamps
Properties timestamps = readTimestamps();
if (timestamps.isEmpty()) {
diff --git a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java
index 337d41a..cf3feb3 100644
--- a/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java
+++ b/bundles/org.eclipse.equinox.p2.reconciler.dropins/src/org/eclipse/equinox/internal/p2/reconciler/dropins/ProfileSynchronizer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 IBM Corporation and others. All rights reserved.
+ * Copyright (c) 2007, 2013 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
@@ -7,11 +7,10 @@
* Contributors:
* IBM Corporation - initial implementation and ideas
* Sonatype, Inc. - ongoing development
+ * RedHat, Inc. - Bug 397216
******************************************************************************/
package org.eclipse.equinox.internal.p2.reconciler.dropins;
-import org.eclipse.equinox.p2.metadata.IRequirement;
-
import java.io.*;
import java.net.*;
import java.util.*;
@@ -56,6 +55,9 @@ public class ProfileSynchronizer {
private static final String CACHE_EXTENSIONS = "org.eclipse.equinox.p2.cache.extensions"; //$NON-NLS-1$
private static final String PIPE = "|"; //$NON-NLS-1$
private static final String EXPLANATION = "org.eclipse.equinox.p2.director.explain"; //$NON-NLS-1$
+
+ static final String PROP_IGNORE_USER_CONFIGURATION = "eclipse.ignoreUserConfiguration"; //$NON-NLS-1$
+
final IProfile profile;
final Map<String, IMetadataRepository> repositoryMap;
@@ -396,6 +398,12 @@ public class ProfileSynchronizer {
* Read the values of the stored timestamps that we use for caching.
*/
private void readTimestamps() {
+ if (Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(PROP_IGNORE_USER_CONFIGURATION))) {
+ timestamps = new HashMap<String, String>();
+ Activator.trace("Master profile changed."); //$NON-NLS-1$
+ Activator.trace("Performing reconciliation."); //$NON-NLS-1$
+ return;
+ }
File file = Activator.getContext().getDataFile(TIMESTAMPS_FILE_PREFIX + profile.getProfileId().hashCode());
try {
InputStream is = new BufferedInputStream(new FileInputStream(file));
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTest.java
new file mode 100644
index 0000000..0d964ac
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTest.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Red Hat, Inc. 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: Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.equinox.p2.tests.simpleconfigurator;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+import org.eclipse.equinox.internal.simpleconfigurator.SimpleConfiguratorImpl;
+import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
+
+public class SimpleConfiguratorTest extends AbstractProvisioningTest {
+
+ private URL relativeURL;
+ private File userConfiguration;
+ private File masterConfguration;
+ private URL[] sharedConfiguration = new URL[2];
+ private URL[] localConfiguration = new URL[1];
+ private SimpleConfiguratorImpl configurator;
+
+ public void setUp() throws Exception {
+ relativeURL = new URL("file://bundles.info");
+ userConfiguration = getTestData("userConfiguration", "testData/simpleconfigurator/user");
+ sharedConfiguration[0] = userConfiguration.toURL();
+ masterConfguration = getTestData("userConfiguration", "testData/simpleconfigurator/master");
+ sharedConfiguration[1] = masterConfguration.toURL();
+ localConfiguration[0] = sharedConfiguration[1];
+ configurator = getSimpleConfigurator();
+ }
+
+ private SimpleConfiguratorImpl getSimpleConfigurator() {
+ return new SimpleConfiguratorImpl(null, null);
+ }
+
+ private void storeTimestamp(long timestamp) throws IOException {
+ File f = new File(userConfiguration.getParent(), SimpleConfiguratorImpl.BASE_TIMESTAMP_FILE_BUNDLESINFO);
+ Properties p = new Properties();
+ p.put(SimpleConfiguratorImpl.KEY_BUNDLESINFO_TIMESTAMP, "" + timestamp);
+ p.store(new FileWriter(f), "");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ System.setProperty(SimpleConfiguratorImpl.PROP_IGNORE_USER_CONFIGURATION, "false");
+ File f = new File(userConfiguration.getParent(), SimpleConfiguratorImpl.BASE_TIMESTAMP_FILE_BUNDLESINFO);
+ if (f.exists()) {
+ f.delete();
+ }
+ super.tearDown();
+ }
+
+ private void assertIsPropertySet(boolean set) {
+ assertEquals(set, Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(SimpleConfiguratorImpl.PROP_IGNORE_USER_CONFIGURATION)));
+ }
+
+ public void testSimpleConfiguration() throws MalformedURLException {
+ assertEquals(localConfiguration[0], configurator.chooseConfigurationURL(relativeURL, localConfiguration));
+ assertIsPropertySet(false);
+ }
+
+ public void testNotExistingConfigiration() throws MalformedURLException {
+ assertNull(configurator.chooseConfigurationURL(relativeURL, new URL[] {new File(".", "notexisting").toURL()}));
+ assertIsPropertySet(false);
+ }
+
+ public void testSharedConfigurationUserNotExisting() throws MalformedURLException {
+ sharedConfiguration[0] = new File(".", "notexisting").toURL();
+ assertEquals(sharedConfiguration[1], configurator.chooseConfigurationURL(relativeURL, sharedConfiguration));
+ assertIsPropertySet(false);
+ }
+
+ // no timestamp -> pick user
+ public void testSharedConfigurationNoTimestamp() throws MalformedURLException {
+ assertEquals(sharedConfiguration[0], configurator.chooseConfigurationURL(relativeURL, sharedConfiguration));
+ assertIsPropertySet(false);
+ }
+
+ //master modified -> pick master
+ public void testSharedConfigurationMasterModified() throws IOException {
+ storeTimestamp(1000);
+ assertEquals(sharedConfiguration[1], configurator.chooseConfigurationURL(relativeURL, sharedConfiguration));
+ assertIsPropertySet(true);
+ }
+
+ //master not modified -> pick user
+ public void testSharedConfigurationMasterUnmodified() throws IOException {
+ storeTimestamp(new File(masterConfguration, relativeURL.getFile()).lastModified());
+ assertEquals(sharedConfiguration[0], configurator.chooseConfigurationURL(relativeURL, sharedConfiguration));
+ assertIsPropertySet(false);
+ }
+
+ //master not modified, but property present -> pick master
+ public void testSharedConfigurationMasterUnmodifiedPropertySet() throws IOException {
+ System.setProperty(SimpleConfiguratorImpl.PROP_IGNORE_USER_CONFIGURATION, "true");
+ storeTimestamp(new File(masterConfguration, relativeURL.getFile()).lastModified());
+ assertEquals(sharedConfiguration[1], configurator.chooseConfigurationURL(relativeURL, sharedConfiguration));
+ assertIsPropertySet(true);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTests.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTests.java
index a3b448f..454f30d 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTests.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/simpleconfigurator/SimpleConfiguratorTests.java
@@ -16,6 +16,7 @@ public class SimpleConfiguratorTests {
public static Test suite() {
TestSuite suite = new TestSuite("Tests for org.eclipse.equinox.simpleconfigurator");
//$JUnit-BEGIN$
+ suite.addTestSuite(SimpleConfiguratorTest.class);
suite.addTestSuite(SimpleConfiguratorUtilsTest.class);
suite.addTestSuite(BundlesTxtTest.class);
suite.addTestSuite(NonExclusiveMode.class);
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/master/bundles.info b/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/master/bundles.info
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/master/bundles.info
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/user/bundles.info b/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/user/bundles.info
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/simpleconfigurator/user/bundles.info
diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
index 785a018..06186bb 100644
--- a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
+++ b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2011 IBM Corporation and others.
+ * Copyright (c) 2008, 2013 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB - ongoing development
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.sdk.scheduler;
@@ -22,8 +23,11 @@ import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQuery;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.ui.IStartup;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.*;
import org.eclipse.ui.statushandlers.StatusManager;
/**
@@ -78,10 +82,46 @@ public class AutomaticUpdateScheduler implements IStartup {
}
public void earlyStartup() {
+ if (baseChanged())
+ return;
garbageCollect();
scheduleUpdate();
}
+ Shell getWorkbenchWindowShell() {
+ IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ return activeWindow != null ? activeWindow.getShell() : null;
+
+ }
+
+ private boolean baseChanged() {
+ IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(AutomaticUpdatePlugin.getContext(), IProvisioningAgent.SERVICE_NAME);
+ IProfileRegistry registry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);
+ //Access the running profile to force its reinitialization if it has not been done.
+ registry.getProfile(IProfileRegistry.SELF);
+ String resetState = (String) agent.getService(IProfileRegistry.SERVICE_SHARED_INSTALL_NEW_TIMESTAMP);
+ if (resetState == null)
+ return false;
+
+ final String PREF_MIGRATION_DIALOG_SHOWN = "migrationDialogShown"; //$NON-NLS-1$
+
+ //Have we already shown the migration dialog
+ if (AutomaticUpdatePlugin.getDefault().getPreferenceStore().getString(PREF_MIGRATION_DIALOG_SHOWN) == resetState)
+ return false;
+
+ //Remember that we are showing the migration dialog
+ AutomaticUpdatePlugin.getDefault().getPreferenceStore().setValue(PREF_MIGRATION_DIALOG_SHOWN, resetState);
+ AutomaticUpdatePlugin.getDefault().savePreferences();
+
+ Display d = Display.getDefault();
+ d.asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openWarning(getWorkbenchWindowShell(), "Installation modified", "An upgrade of the eclipse installation you are using has been performed. The plugins you had installed have been uninstalled."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+ return true;
+ }
+
/**
* Invokes the garbage collector to discard unused plugins, if specified by a
* corresponding preference.
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/p2/ui/RepositoryManipulationPage.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/p2/ui/RepositoryManipulationPage.java
index 73b63c7..914f56c 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/p2/ui/RepositoryManipulationPage.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/p2/ui/RepositoryManipulationPage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 IBM Corporation and others.
+ * Copyright (c) 2007, 2013 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB (Pascal Rapicault) - bug 398539
*******************************************************************************/
package org.eclipse.equinox.p2.ui;
@@ -774,7 +775,7 @@ public class RepositoryManipulationPage extends PreferencePage implements IWorkb
};
int retCode = dialog.open();
- if (retCode == Window.OK) {
+ if (retCode == Window.OK && dialog.getLocation() != null) {
selected[0].setNickname(dialog.getName());
selected[0].setLocation(dialog.getLocation());
if (dialog.getLocation().equals(existingLocation)) {
diff --git a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
index c6748e9..55e1743 100644
--- a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
+++ b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
@@ -1,10 +1,13 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 IBM Corporation and others. All rights reserved.
+ * Copyright (c) 2007, 2013 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
+ *
+ * Ericsson AB (Pascal Rapicault) - Bug 397216 -[Shared] Better shared
+ * configuration change discovery
*******************************************************************************/
package org.eclipse.equinox.internal.simpleconfigurator.manipulator;
@@ -42,8 +45,10 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
public static final String PROP_KEY_EXCLUSIVE_INSTALLATION = "org.eclipse.equinox.simpleconfigurator.exclusiveInstallation"; //$NON-NLS-1$
public static final String CONFIG_LIST = "bundles.info"; //$NON-NLS-1$
+ public static final String CONFIG_FOLDER = "configuration"; //$NON-NLS-1$
public static final String CONFIGURATOR_FOLDER = "org.eclipse.equinox.simpleconfigurator"; //$NON-NLS-1$
public static final String PROP_KEY_CONFIGURL = "org.eclipse.equinox.simpleconfigurator.configUrl"; //$NON-NLS-1$
+ public static final String SHARED_BUNDLES_INFO = CONFIG_FOLDER + File.separatorChar + CONFIGURATOR_FOLDER + File.separatorChar + CONFIG_LIST;
private Set manipulators = new HashSet();
@@ -63,7 +68,7 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
if (manipulator.getLauncherData().getLauncher() != null) {
baseDir = manipulator.getLauncherData().getLauncher().getParentFile();
} else {
- throw new IllegalStateException("All of fwConfigFile, home, launcher are not set.");
+ throw new IllegalStateException("All of fwConfigFile, home, launcher are not set."); //$NON-NLS-1$
}
}
} else {
@@ -393,6 +398,33 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
return;
}
SimpleConfiguratorManipulatorUtils.writeConfiguration(simpleInfos, outputFile);
+ if (CONFIG_LIST.equals(outputFile.getName()) && isSharedInstallSetup(URIUtil.toFile(installArea), outputFile))
+ rememberSharedBundlesInfoTimestamp(installArea, outputFile.getParentFile());
+ }
+
+ private void rememberSharedBundlesInfoTimestamp(URI installArea, File outputFolder) {
+ if (installArea == null)
+ return;
+
+ File sharedBundlesInfo = new File(URIUtil.append(installArea, SHARED_BUNDLES_INFO));
+ if (!sharedBundlesInfo.exists())
+ return;
+
+ Properties timestampToPersist = new Properties();
+ timestampToPersist.put(SimpleConfiguratorImpl.KEY_BUNDLESINFO_TIMESTAMP, Long.toString(sharedBundlesInfo.lastModified()));
+ OutputStream os = null;
+ try {
+ try {
+ File outputFile = new File(outputFolder, SimpleConfiguratorImpl.BASE_TIMESTAMP_FILE_BUNDLESINFO);
+ os = new BufferedOutputStream(new FileOutputStream(outputFile));
+ timestampToPersist.store(os, "Written by " + this.getClass()); //$NON-NLS-1$
+ } finally {
+ if (os != null)
+ os.close();
+ }
+ } catch (IOException e) {
+ return;
+ }
}
private org.eclipse.equinox.internal.simpleconfigurator.utils.BundleInfo[] convertBundleInfos(BundleInfo[] configuration, URI installArea) {
@@ -402,7 +434,7 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
BundleInfo bundleInfo = configuration[i];
URI location = bundleInfo.getLocation();
if (bundleInfo.getSymbolicName() == null || bundleInfo.getVersion() == null || location == null)
- throw new IllegalArgumentException("Cannot persist bundleinfo: " + bundleInfo.toString());
+ throw new IllegalArgumentException("Cannot persist bundleinfo: " + bundleInfo.toString()); //$NON-NLS-1$
//only need to make a new BundleInfo if we are changing it.
if (installArea != null)
location = URIUtil.makeRelative(location, installArea);
@@ -492,13 +524,17 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
File configFile = getConfigFile(manipulator);
File installArea = ParserUtils.getOSGiInstallArea(Arrays.asList(manipulator.getLauncherData().getProgramArgs()), manipulator.getConfigData().getProperties(), manipulator.getLauncherData());
- BundleInfo[] toInstall = null;
- try {
- //input stream will be closed for us
- toInstall = loadConfiguration(new FileInputStream(configFile), installArea.toURI());
- } catch (FileNotFoundException e) {
- //no file, just return an empty list
- toInstall = new BundleInfo[0];
+ BundleInfo[] toInstall = new BundleInfo[0];
+
+ boolean isShared = isSharedInstallSetup(installArea, configFile);
+ if (!isShared || (isShared && !hasBaseChanged(installArea.toURI(), configFile.getParentFile()))) {
+ try {
+ //input stream will be closed for us
+ toInstall = loadConfiguration(new FileInputStream(configFile), installArea.toURI());
+ } catch (FileNotFoundException e) {
+ //no file, just return an empty list
+ toInstall = new BundleInfo[0];
+ }
}
List toUninstall = new LinkedList();
@@ -538,4 +574,43 @@ public class SimpleConfiguratorManipulatorImpl implements SimpleConfiguratorMani
if (outputFile.getParentFile().isDirectory())
outputFile.getParentFile().delete();
}
+
+ private boolean hasBaseChanged(URI installArea, File outputFolder) {
+ String rememberedTimestamp;
+ try {
+ rememberedTimestamp = (String) loadProperties(new File(outputFolder, SimpleConfiguratorImpl.BASE_TIMESTAMP_FILE_BUNDLESINFO)).get(SimpleConfiguratorImpl.KEY_BUNDLESINFO_TIMESTAMP);
+ } catch (IOException e) {
+ return false;
+ }
+ if (rememberedTimestamp == null)
+ return false;
+
+ File sharedBundlesInfo = new File(URIUtil.append(installArea, SHARED_BUNDLES_INFO));
+ if (!sharedBundlesInfo.exists())
+ return true;
+ return !String.valueOf(sharedBundlesInfo.lastModified()).equals(rememberedTimestamp);
+ }
+
+ private boolean isSharedInstallSetup(File installArea, File outputFile) {
+ //An instance is treated as shared if the bundles.info file is not located in the install area.
+ return !new File(installArea, SHARED_BUNDLES_INFO).equals(outputFile);
+ }
+
+ private Properties loadProperties(File inputFile) throws FileNotFoundException, IOException {
+ Properties props = new Properties();
+ InputStream is = null;
+ try {
+ is = new FileInputStream(inputFile);
+ props.load(is);
+ } finally {
+ try {
+ if (is != null)
+ is.close();
+ } catch (IOException e) {
+ //Do nothing
+ }
+ is = null;
+ }
+ return props;
+ }
}
diff --git a/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/SimpleConfiguratorImpl.java b/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/SimpleConfiguratorImpl.java
index dbd2aec..70d3b4c 100644
--- a/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/SimpleConfiguratorImpl.java
+++ b/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/SimpleConfiguratorImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 IBM Corporation and others.
+ * Copyright (c) 2007, 2013 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
@@ -7,13 +7,14 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Ericsson AB (Pascal Rapicault) - Bug 397216 -[Shared] Better shared configuration change discovery
*******************************************************************************/
package org.eclipse.equinox.internal.simpleconfigurator;
-import java.io.File;
-import java.io.IOException;
-import java.net.*;
-import java.util.List;
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
import org.eclipse.equinox.internal.provisional.configurator.Configurator;
import org.eclipse.equinox.internal.simpleconfigurator.utils.*;
import org.osgi.framework.Bundle;
@@ -42,6 +43,12 @@ public class SimpleConfiguratorImpl implements Configurator {
private ConfigApplier configApplier;
private Bundle bundle;
+ //for change detection in the base when running in shared install mode
+ private static final long NO_TIMESTAMP = -1;
+ public static final String BASE_TIMESTAMP_FILE_BUNDLESINFO = ".baseBundlesInfoTimestamp"; //$NON-NLS-1$
+ public static final String KEY_BUNDLESINFO_TIMESTAMP = "bundlesInfoTimestamp";
+ public static final String PROP_IGNORE_USER_CONFIGURATION = "eclipse.ignoreUserConfiguration"; //$NON-NLS-1$
+
public SimpleConfiguratorImpl(BundleContext context, Bundle bundle) {
this.context = context;
this.bundle = bundle;
@@ -80,27 +87,10 @@ public class SimpleConfiguratorImpl implements Configurator {
//if it is an relative file URL, then resolve it against the configuration area
// TODO Support relative file URLs when not on Equinox
URL[] configURL = EquinoxUtils.getConfigAreaURL(context);
- if (configURL != null) {
- File userConfig = new File(configURL[0].getFile(), url.getFile());
- if (configURL.length == 1)
- return userConfig.exists() ? userConfig.toURL() : null;
-
- File sharedConfig = new File(configURL[1].getFile(), url.getFile());
- if (!userConfig.exists())
- return sharedConfig.exists() ? sharedConfig.toURL() : null;
-
- if (!sharedConfig.exists())
- return userConfig.toURL();
-
- URI base = EquinoxUtils.getInstallLocationURI(context);
-
- URL sharedConfigURL = sharedConfig.toURL();
- List sharedBundles = SimpleConfiguratorUtils.readConfiguration(sharedConfigURL, base);
- URL userConfigURL = userConfig.toURL();
- List userBundles = SimpleConfiguratorUtils.readConfiguration(userConfigURL, base);
-
- return (userBundles.containsAll(sharedBundles)) ? userConfigURL : sharedConfigURL;
+ URL result = chooseConfigurationURL(url, configURL);
+ if (result != null) {
+ return result;
}
} catch (MalformedURLException e) {
return null;
@@ -116,6 +106,69 @@ public class SimpleConfiguratorImpl implements Configurator {
return null;
}
+ /**
+ * This method is public for testing purposes only.
+ * @param relativeURL - a relative URL of the configuration
+ * @param configURL - an array of parent config URLs to which relativeURL can be appended.
+ */
+ public URL chooseConfigurationURL(URL relativeURL, URL[] configURL) throws MalformedURLException {
+ if (configURL != null) {
+ File userConfig = new File(configURL[0].getFile(), relativeURL.getFile());
+ if (configURL.length == 1)
+ return userConfig.exists() ? userConfig.toURL() : null;
+
+ File sharedConfig = new File(configURL[1].getFile(), relativeURL.getFile());
+ if (!userConfig.exists())
+ return sharedConfig.exists() ? sharedConfig.toURL() : null;
+
+ if (!sharedConfig.exists())
+ return userConfig.toURL();
+
+ if (Boolean.TRUE.toString().equals(System.getProperty(PROP_IGNORE_USER_CONFIGURATION)))
+ return sharedConfig.toURL();
+
+ long sharedBundlesInfoTimestamp = getCurrentBundlesInfoBaseTimestamp(sharedConfig);
+ long lastKnownBaseTimestamp = getLastKnownBundlesInfoBaseTimestamp(userConfig.getParentFile());
+
+ if (lastKnownBaseTimestamp == sharedBundlesInfoTimestamp || lastKnownBaseTimestamp == NO_TIMESTAMP) {
+ return userConfig.toURL();
+ } else {
+ System.setProperty(PROP_IGNORE_USER_CONFIGURATION, Boolean.TRUE.toString());
+ return sharedConfig.toURL();
+ }
+ }
+ return null;
+ }
+
+ private long getLastKnownBundlesInfoBaseTimestamp(File configFolder) {
+ File storedSharedTimestamp = new File(configFolder, BASE_TIMESTAMP_FILE_BUNDLESINFO);
+ if (!storedSharedTimestamp.exists())
+ return NO_TIMESTAMP;
+
+ Properties p = new Properties();
+ InputStream is = null;
+ try {
+ try {
+ is = new BufferedInputStream(new FileInputStream(storedSharedTimestamp));
+ p.load(is);
+ if (p.get(KEY_BUNDLESINFO_TIMESTAMP) != null) {
+ return Long.valueOf((String) p.get(KEY_BUNDLESINFO_TIMESTAMP)).longValue();
+ }
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ return NO_TIMESTAMP;
+ }
+ return NO_TIMESTAMP;
+ }
+
+ private long getCurrentBundlesInfoBaseTimestamp(File sharedBundlesInfo) {
+ if (!sharedBundlesInfo.exists())
+ return NO_TIMESTAMP;
+ return sharedBundlesInfo.lastModified();
+ }
+
public void applyConfiguration(URL url) throws IOException {
synchronized (configurationLock) {
if (Activator.DEBUG)