diff --git a/.classpath b/.classpath
index 130468185..8ec5596fa 100755
--- a/.classpath
+++ b/.classpath
@@ -31,7 +31,7 @@
-
+
@@ -59,7 +59,7 @@
-
+
@@ -78,9 +78,10 @@
-
+
+
diff --git a/build.xml b/build.xml
index 49170e2fb..a8d0fb6db 100644
--- a/build.xml
+++ b/build.xml
@@ -1088,7 +1088,7 @@
bundle-demuxcontactsource, bundle-muc,
bundle-desktoputil,bundle-globaldisplaydetails,
bundle-plugin-propertieseditor,bundle-plugin-accountinfo,
- bundle-guava"/>
+ bundle-guava,bundle-hsql"/>
@@ -1386,6 +1386,10 @@
+
+
+
+
BundleContext in which the configuration bundle has been
- * started and has not been stopped yet.
+ * The currently registered {@link ConfigurationService} instance.
*/
- private static BundleContext bundleContext;
+ private ConfigurationService cs;
/**
* Starts the configuration service
@@ -44,20 +47,29 @@ public class ConfigurationActivator
public void start(BundleContext bundleContext)
throws Exception
{
- ConfigurationActivator.bundleContext = bundleContext;
-
- ConfigurationService configurationService
- = LibJitsi.getConfigurationService();
-
- if (configurationService != null)
+ FileAccessService fas
+ = ServiceUtils.getService(bundleContext, FileAccessService.class);
+ File useDatabaseConfig = fas.getPrivatePersistentFile(
+ ".usedatabaseconfig",
+ FileCategory.PROFILE);
+
+ // BETA: if the marker file exists, use the database configuration
+ if (useDatabaseConfig.exists())
{
- bundleContext.registerService(
- ConfigurationService.class.getName(),
- configurationService,
- null);
-
- fixPermissions(configurationService);
+ logger.info("Using database configuration store.");
+ this.cs = new JdbcConfigService(fas);
+ }
+ else
+ {
+ this.cs = LibJitsi.getConfigurationService();
}
+
+ bundleContext.registerService(
+ ConfigurationService.class.getName(),
+ this.cs,
+ null);
+
+ fixPermissions(this.cs);
}
/**
@@ -72,18 +84,8 @@ public void start(BundleContext bundleContext)
public void stop(BundleContext bundleContext)
throws Exception
{
- }
-
- /**
- * Gets the BundleContext in which the configuration bundle has
- * been started and has not been stopped yet.
- *
- * @return the BundleContext in which the configuration bundle has
- * been started and has not been stopped yet
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
+ this.cs.storeConfiguration();
+ this.cs = null;
}
/**
diff --git a/src/net/java/sip/communicator/impl/configuration/JdbcConfigService.java b/src/net/java/sip/communicator/impl/configuration/JdbcConfigService.java
new file mode 100644
index 000000000..e75068b70
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/configuration/JdbcConfigService.java
@@ -0,0 +1,910 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.configuration;
+
+import java.beans.*;
+import java.io.*;
+import java.sql.*;
+import java.sql.Statement;
+import java.util.*;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.fileaccess.*;
+import org.jitsi.util.*;
+
+import com.google.common.collect.*;
+
+/**
+ * Implementation of the {@link ConfigurationService} based on JDBC.
+ *
+ * @author Ingo Bauersachs
+ */
+public final class JdbcConfigService
+ implements ConfigurationService
+{
+ /**
+ * The Logger used by this class.
+ */
+ private final Logger logger
+ = Logger.getLogger(JdbcConfigService.class);
+
+ /**
+ * Name of the file containing default properties.
+ */
+ private static final String DEFAULT_PROPS_FILE_NAME
+ = "jitsi-defaults.properties";
+
+ /**
+ * Name of the file containing overrides (possibly set by the distributor)
+ * for any of the default properties.
+ */
+ private static final String DEFAULT_OVERRIDES_PROPS_FILE_NAME
+ = "jitsi-default-overrides.properties";
+
+ /**
+ * A set of immutable properties deployed with the application during
+ * install time. The properties in this file will be impossible to override
+ * and attempts to do so will simply be ignored.
+ * @see #defaultProperties
+ */
+ private Map immutableDefaultProperties
+ = new HashMap();
+
+ /**
+ * A set of properties deployed with the application during install time.
+ * Contrary to the properties in {@link #immutableDefaultProperties} the
+ * ones in this map can be overridden with call to the
+ * setProperty() methods. Still, re-setting one of these properties
+ * to null would cause for its initial value to be restored.
+ */
+ private Map defaultProperties
+ = new HashMap();
+
+ /**
+ * Registered property change listeners that may veto a change.
+ */
+ private SetMultimap vetoListeners
+ = HashMultimap.create();
+
+ /**
+ * Registered property change listeners.
+ */
+ private SetMultimap listeners
+ = HashMultimap.create();
+
+ /**
+ * Connection to the JDBC database.
+ */
+ private Connection connection;
+
+ // SQL statements for queries against the database
+ private PreparedStatement selectExact;
+ private PreparedStatement selectLike;
+ private PreparedStatement selectAll;
+ private PreparedStatement insertOrUpdate;
+ private PreparedStatement delete;
+
+ /**
+ * Reference to the {@link FileAccessService}.
+ */
+ private FileAccessService fas;
+
+ /**
+ * Creates a new instance of this class.
+ * @param fas Reference to the {@link FileAccessService}.
+ * @throws Exception
+ */
+ public JdbcConfigService(FileAccessService fas) throws Exception
+ {
+ this.fas = fas;
+ File dataFile = fas.getPrivatePersistentFile(
+ "props.hsql.script",
+ FileCategory.PROFILE);
+ File oldProps = fas.getPrivatePersistentFile(
+ "sip-communicator.properties",
+ FileCategory.PROFILE);
+
+ // if the file for the current database does not exist yet but
+ // the previous properties-based file is there, migrate it
+ boolean migrate = false;
+ if (!dataFile.exists() && oldProps.exists())
+ {
+ migrate = true;
+ }
+
+ // open the connection
+ Class.forName("org.hsqldb.jdbc.JDBCDriver");
+ checkConnection();
+
+ // then do the actual migration
+ if (migrate)
+ {
+ Properties p = new Properties();
+ p.load(new FileInputStream(oldProps));
+
+ this.connection.setAutoCommit(false);
+ for (Map.Entry