Bug 521542 - org.osgi.framework.storage is used even when
osgi.configuration.area is set

Log a warning when this occurs.

Had to add an exceptions map that can be used during bootstrap
when there is no log service to log to yet.  This allowed for 
fixing several TODOs where we thought we should be logging but
couldn't because no log service was available yet.
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
index 5129c9f..3eb8f25 100755
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
@@ -39,6 +39,7 @@
 import org.osgi.framework.wiring.*;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
+import org.osgi.service.log.*;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.service.startlevel.StartLevel;
@@ -3094,4 +3095,37 @@
 			}
 		}
 	}
+
+	public void testOverrideEquinoxConfigAreaProp() {
+		File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$
+		Map configuration = new HashMap();
+		configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath());
+		configuration.put(EquinoxLocations.PROP_CONFIG_AREA, config.getAbsolutePath() + "-override");
+		configuration.put(EquinoxConfiguration.PROP_LOG_HISTORY_MAX, "10");
+		Equinox equinox = null;
+		try {
+			equinox = new Equinox(configuration);
+			equinox.init();
+			BundleContext bc = equinox.getBundleContext();
+			LogReaderService logReader = bc.getService(bc.getServiceReference(LogReaderService.class));
+			Enumeration<LogEntry> logs = logReader.getLog();
+			assertTrue("No logs found.", logs.hasMoreElements());
+			LogEntry entry = logs.nextElement();
+			assertEquals("Wrong log level.", LogLevel.WARN, entry.getLogLevel());
+			assertTrue("Wrong message found: " + entry.getMessage(), entry.getMessage().contains(EquinoxLocations.PROP_CONFIG_AREA));
+		} catch (BundleException e) {
+			fail("Failed init", e);
+		} finally {
+			try {
+				if (equinox != null) {
+					equinox.stop();
+					equinox.waitForStop(1000);
+				}
+			} catch (BundleException e) {
+				fail("Failed to stop framework.", e);
+			} catch (InterruptedException e) {
+				fail("Failed to stop framework.", e);
+			}
+		}
+	}
 }
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java
index 7283c00..0ce16cd 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2016 IBM Corporation and others.
+ * Copyright (c) 2003, 2017 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
@@ -30,11 +30,13 @@
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.eclipse.core.runtime.internal.adaptor.ConsoleManager;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
 import org.eclipse.osgi.internal.debug.Debug;
 import org.eclipse.osgi.internal.debug.FrameworkDebugOptions;
 import org.eclipse.osgi.internal.hookregistry.HookRegistry;
 import org.eclipse.osgi.internal.location.EquinoxLocations;
 import org.eclipse.osgi.internal.location.LocationHelper;
+import org.eclipse.osgi.internal.log.EquinoxLogServices;
 import org.eclipse.osgi.internal.messages.Msg;
 import org.eclipse.osgi.service.datalocation.Location;
 import org.eclipse.osgi.service.debug.DebugOptions;
@@ -112,6 +114,8 @@
 	public final boolean CLASS_CERTIFICATE;
 	public final boolean PARALLEL_CAPABLE;
 
+	private final Map<Throwable, Integer> exceptions = new LinkedHashMap<>(0);
+
 	// JVM os.arch property name
 	public static final String PROP_JVM_OS_ARCH = "os.arch"; //$NON-NLS-1$
 	// JVM os.name property name
@@ -230,7 +234,10 @@
 		private final Map<String, Object> initialConfig;
 		private final Properties localConfig;
 
-		public ConfigValues(Map<String, ?> initialConfiguration) {
+		private final Map<Throwable, Integer> exceptions;
+
+		public ConfigValues(Map<String, ?> initialConfiguration, Map<Throwable, Integer> exceptions) {
+			this.exceptions = exceptions;
 			this.initialConfig = initialConfiguration == null ? new HashMap<String, Object>(0) : new HashMap<>(initialConfiguration);
 			Object useSystemPropsValue = initialConfig.get(PROP_USE_SYSTEM_PROPERTIES);
 			this.useSystemProperties = useSystemPropsValue == null ? false : Boolean.parseBoolean(useSystemPropsValue.toString());
@@ -288,7 +295,7 @@
 				// Verify type compatibility.
 				Long.parseLong(getConfiguration(PROP_STATE_SAVE_DELAY_INTERVAL));
 			} catch (NumberFormatException e) {
-				// TODO Consider logging here.
+				exceptions.put(e, FrameworkLogEntry.ERROR);
 				// The specified value is not type compatible. Use the default.
 				setConfiguration(PROP_STATE_SAVE_DELAY_INTERVAL, DEFAULT_STATE_SAVE_DELAY_INTERVAL);
 			}
@@ -329,9 +336,12 @@
 				} finally {
 					in.close();
 				}
+			} catch (FileNotFoundException e) {
+				// TODO probably should log, but the common case for non-eclipse
+				// environments would be to not have a config.ini ...
 			} catch (IOException e) {
-				// its ok if there is no file.  We'll just use the defaults for everything
-				// TODO but it might be nice to log something with gentle wording (i.e., it is not an error)
+				// We'll just use the defaults for everything but log the exception on reading
+				exceptions.put(e, FrameworkLogEntry.WARNING);
 			}
 			return substituteVars(result);
 		}
@@ -497,15 +507,15 @@
 		// Care must be taken to bootstrap of the config values properly
 		// A separate class is used to hold the configuration maps so that we can pass them
 		// to the EquionxLocations before the EquinoxConfiguration has been fully constructed
-		this.configValues = new ConfigValues(initialConfiguration);
+		this.configValues = new ConfigValues(initialConfiguration, exceptions);
 
 		// We need to initialize some properties always before constructing the EquinoxLocations
 		initializeProperties();
 
-		// At this point we do not know if we want to debug locations because we have not detemined if osgi.debug is set yet
+		// At this point we do not know if we want to debug locations because we have not determined if osgi.debug is set yet
 		// We use an AttomicBoolean to hold the setting so we can set it after the config.ini has been loaded
 		AtomicBoolean debugLocations = new AtomicBoolean();
-		this.equinoxLocations = new EquinoxLocations(this.configValues, this.hookRegistry.getContainer(), debugLocations);
+		this.equinoxLocations = new EquinoxLocations(this.configValues, this.hookRegistry.getContainer(), debugLocations, exceptions);
 		this.configValues.loadConfigIni(getConfigIni(equinoxLocations, false));
 		this.configValues.loadConfigIni(getConfigIni(equinoxLocations, true));
 		this.configValues.finalizeValues();
@@ -535,7 +545,7 @@
 					loadDevProperties(LocationHelper.getStream(location));
 					devMode = true;
 				} catch (IOException e) {
-					// TODO consider logging
+					exceptions.put(e, FrameworkLogEntry.ERROR);
 				}
 
 			} catch (MalformedURLException e) {
@@ -858,7 +868,7 @@
 		try {
 			props.load(input);
 		} catch (IOException e) {
-			// TODO consider logging here
+			exceptions.put(e, FrameworkLogEntry.ERROR);
 		} finally {
 			if (input != null)
 				try {
@@ -1159,4 +1169,11 @@
 	public EquinoxLocations getEquinoxLocations() {
 		return equinoxLocations;
 	}
+
+	void logMessages(EquinoxLogServices logServices) {
+		for (Map.Entry<Throwable, Integer> exception : exceptions.entrySet()) {
+			logServices.log(EquinoxContainer.NAME, exception.getValue(), exception.getKey().getMessage(), exception.getKey());
+		}
+		exceptions.clear();
+	}
 }
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
index b81704c..4312a0f 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
@@ -63,6 +63,7 @@
 	public EquinoxContainer(Map<String, ?> configuration) {
 		this.equinoxConfig = new EquinoxConfiguration(configuration, new HookRegistry(this));
 		this.logServices = new EquinoxLogServices(this.equinoxConfig);
+		this.equinoxConfig.logMessages(this.logServices);
 		this.equinoxConfig.getHookRegistry().initialize();
 		try {
 			this.storage = Storage.createStorage(this);
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/location/EquinoxLocations.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/location/EquinoxLocations.java
index 8d623a7..1869cfd 100755
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/location/EquinoxLocations.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/location/EquinoxLocations.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 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
@@ -14,8 +14,10 @@
 import java.io.*;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
 import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
 import org.eclipse.osgi.internal.framework.EquinoxConfiguration.ConfigValues;
 import org.eclipse.osgi.internal.framework.EquinoxContainer;
@@ -69,7 +71,7 @@
 	private final Location instanceLocation;
 	private final Location eclipseHomeLocation;
 
-	public EquinoxLocations(ConfigValues equinoxConfig, EquinoxContainer container, AtomicBoolean debugLocations) {
+	public EquinoxLocations(ConfigValues equinoxConfig, EquinoxContainer container, AtomicBoolean debugLocations, Map<Throwable, Integer> exceptions) {
 		this.equinoxConfig = equinoxConfig;
 		this.container = container;
 		this.debugLocations = debugLocations;
@@ -77,8 +79,14 @@
 		// Initializes the Location objects for the LocationManager.
 		// set the osgi storage area if it exists
 		String osgiStorage = equinoxConfig.getConfiguration(Constants.FRAMEWORK_STORAGE);
-		if (osgiStorage != null)
+		if (osgiStorage != null) {
+			if (equinoxConfig.getConfiguration(PROP_CONFIG_AREA) != null) {
+				exceptions.put(new IllegalArgumentException(String.format( //
+						"The property '%s' with the value '%s' is being overriden by the OSGi standard configuration property '%s' with the value '%s'.", //$NON-NLS-1$
+						PROP_CONFIG_AREA, equinoxConfig.getConfiguration(PROP_CONFIG_AREA), Constants.FRAMEWORK_STORAGE, osgiStorage)), FrameworkLogEntry.WARNING);
+			}
 			equinoxConfig.setConfiguration(PROP_CONFIG_AREA, osgiStorage);
+		}
 		// do install location initialization first since others may depend on it
 		// assumes that the property is already set
 		installLocation = buildLocation(PROP_INSTALL_AREA, null, "", true, false, null); //$NON-NLS-1$