From 3f4d6d5bb6b46947a11d8337d12e2c36c1421dee Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 10:21:49 +0100 Subject: [PATCH 01/12] Switch database connection to use full connection URL --- .../channelserver/ChannelsEngine.java | 2 +- .../channelserver/Configuration.java | 398 ++++++++++-------- .../db/DefaultNodeStoreFactoryImpl.java | 6 +- .../db/JDBCConnectionFactory.java | 10 +- 4 files changed, 222 insertions(+), 194 deletions(-) diff --git a/src/main/java/org/buddycloud/channelserver/ChannelsEngine.java b/src/main/java/org/buddycloud/channelserver/ChannelsEngine.java index 98f8e4ea..50015d29 100644 --- a/src/main/java/org/buddycloud/channelserver/ChannelsEngine.java +++ b/src/main/java/org/buddycloud/channelserver/ChannelsEngine.java @@ -72,7 +72,7 @@ public void initialize(JID jid, ComponentManager manager) throws ComponentExcept private void sendConnectionNotification(JID jid2) throws ComponentException { ArrayList sendTo = - Configuration.getInstance().getNotificationsList( + this.configuration.getNotificationsList( Configuration.NOTIFICATIONS_CONNECTED); Message message = new Message(); message.setFrom(jid); diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index dd2869c2..d3ef5c9a 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -15,216 +15,246 @@ import org.xmpp.packet.JID; public class Configuration extends Properties { - private static final Logger LOGGER = Logger.getLogger(Configuration.class); - - private static final long serialVersionUID = 1L; - - private static final String ARRAY_PROPERTY_SEPARATOR = ";"; - private static final String INVALID_NODE = "Illegal node format"; - - public static final String CONFIGURATION_SERVER_DOMAIN = "server.domain"; - public static final String CONFIGURATION_SERVER_CHANNELS_DOMAIN = "server.domain.channels"; - public static final String CONFIGURATION_SERVER_TOPICS_DOMAIN = "server.domain.topics"; - public static final String CONFIGURATION_LOCAL_DOMAIN_CHECKER = "server.domain.checker"; - - public static final String CONFIGURATION_ADMIN_USERS = "users.admin"; - - public static final String CONFIGURATION_CHANNELS_AUTOSUBSCRIBE = "channels.autosubscribe"; - public static final String CONFIGURATION_CHANNELS_AUTOSUBSCRIBE_AUTOAPPROVE = "channels.autosubscribe.autoapprove"; - public static final String CONFIGURATION_CHANNELS_DEFAULT_AFFILIATION = "channel.configuration.default.affiliation"; - public static final String CONFIGURATION_CHANNELS_DEFAULT_ACCESSMODEL = "channel.configuration.default.accessmodel"; - public static final String CONFIGURATION_CHANNELS_DEFAULT_DESCRIPTION = "channel.configuration.default.description"; - public static final String CONFIGURATION_CHANNELS_DEFAULT_TITLE = "channel.configuration.default.title"; - - public static final String DISCOVERY_USE_DNS = "discovery.dns.enabled"; - - public static final String PERSIST_PRESENCE_DATA = "users.presence.persist"; - - public static final String NOTIFICATIONS_SENDTO = "notifications.sendTo"; - public static final String NOTIFICATIONS_CONNECTED = "notifications.connected"; - - private static final String CONFIGURATION_FILE = "configuration.properties"; - - public static final String PURGE_REMOTE_ON_START = "sync.purge-on-start"; - - public static final String XMPP_PORT = "xmpp.port"; - - public static final String XMPP_HOST = "xmpp.host"; - - private static Configuration instance = null; - - private Collection adminUsers = new ArrayList(); - private Collection autosubscribeChannels = new ArrayList(); - - private Properties conf; - - private Configuration() { - try { - conf = new Properties(); - InputStream confFile = this.getClass().getClassLoader() - .getResourceAsStream(CONFIGURATION_FILE); - if (confFile != null) { - load(confFile); - LOGGER.info("Loaded " + CONFIGURATION_FILE + " from classpath."); - } else { - File f = new File(CONFIGURATION_FILE); - load(new FileInputStream(f)); - LOGGER.info("Loaded " + CONFIGURATION_FILE - + " from working directory."); - } - } catch (Exception e) { - LOGGER.error("Could not load " + CONFIGURATION_FILE + "!"); - System.exit(1); - } - } - - private void setupCollections() { - adminUsers = getJIDArrayProperty(CONFIGURATION_ADMIN_USERS); - autosubscribeChannels = getJIDArrayProperty(CONFIGURATION_CHANNELS_AUTOSUBSCRIBE); - } + private static final Logger LOGGER = Logger.getLogger(Configuration.class); - public Collection getAdminUsers() { - return adminUsers; - } + private static final long serialVersionUID = 1L; - public Collection getAutosubscribeChannels() { - return autosubscribeChannels; - } + private static final String ARRAY_PROPERTY_SEPARATOR = ";"; + private static final String INVALID_NODE = "Illegal node format"; - public static Configuration getInstance() { - if (null == instance) { - instance = new Configuration(); - } - return instance; - } - - public static void reset() { - instance = null; - } + public static final String CONFIGURATION_SERVER_DOMAIN = "server.domain"; + public static final String CONFIGURATION_SERVER_CHANNELS_DOMAIN = "server.domain.channels"; + public static final String CONFIGURATION_SERVER_TOPICS_DOMAIN = "server.domain.topics"; + public static final String CONFIGURATION_LOCAL_DOMAIN_CHECKER = "server.domain.checker"; - public String getProperty(String key) { - return conf.getProperty(key); - } - - @Override - public synchronized Object remove(Object key) { - return conf.remove(key); - } - - public void clear() { - conf.clear(); - } + public static final String CONFIGURATION_ADMIN_USERS = "users.admin"; - public String getProperty(String key, String defaultValue) { - return conf.getProperty(key, defaultValue); - } - - public void putProperty(String key, String value) { - conf.put(key, value); - } + public static final String CONFIGURATION_CHANNELS_AUTOSUBSCRIBE = "channels.autosubscribe"; + public static final String CONFIGURATION_CHANNELS_AUTOSUBSCRIBE_AUTOAPPROVE = + "channels.autosubscribe.autoapprove"; + public static final String CONFIGURATION_CHANNELS_DEFAULT_AFFILIATION = + "channel.configuration.default.affiliation"; + public static final String CONFIGURATION_CHANNELS_DEFAULT_ACCESSMODEL = + "channel.configuration.default.accessmodel"; + public static final String CONFIGURATION_CHANNELS_DEFAULT_DESCRIPTION = + "channel.configuration.default.description"; + public static final String CONFIGURATION_CHANNELS_DEFAULT_TITLE = + "channel.configuration.default.title"; - public void load(InputStream inputStream) throws IOException { - conf.load(inputStream); - setupCollections(); - } + public static final String DISCOVERY_USE_DNS = "discovery.dns.enabled"; - private Collection getStringArrayProperty(String key) { - String prop = getProperty(key); + public static final String PERSIST_PRESENCE_DATA = "users.presence.persist"; - if (null == prop) { - return Collections.emptyList(); - } + public static final String NOTIFICATIONS_SENDTO = "notifications.sendTo"; + public static final String NOTIFICATIONS_CONNECTED = "notifications.connected"; - return Arrays.asList(prop.split(ARRAY_PROPERTY_SEPARATOR)); - } + private static final String CONFIGURATION_FILE = "configuration.properties"; + + public static final String PURGE_REMOTE_ON_START = "sync.purge-on-start"; + + public static final String XMPP_PORT = "xmpp.port"; - private Collection getJIDArrayProperty(String key) { - Collection props = getStringArrayProperty(key); + public static final String XMPP_HOST = "xmpp.host"; - Collection jids = new ArrayList(props.size()); + public static final String DATABASE_ENV = "database"; - for (String prop : props) { - try { - jids.add(new JID(prop)); - } catch (IllegalArgumentException e) { - LOGGER.error(e); - } - } + private static Configuration instance = null; - return jids; + private Collection adminUsers = new ArrayList(); + private Collection autosubscribeChannels = new ArrayList(); + + private Properties conf; + + private Configuration() { + try { + conf = new Properties(); + String databaseConnectionString = System.getenv(DATABASE_ENV); + + if (null == databaseConnectionString) { + loadConfigurationFromFile(); + } else { + loadConfigurationFromDatabase(); + } + + } catch (Exception e) { + LOGGER.error("Could not load configuration"); + System.exit(1); } - - public ArrayList getNotificationsList(String event) { - ArrayList notify = new ArrayList(); - if (!getBooleanProperty(event, false)) { - return notify; - } - String[] users = getProperty(NOTIFICATIONS_SENDTO).split(";"); - JID userJid; - for (String user : users) { - try { - userJid = new JID(user); - notify.add(userJid); - } catch (IllegalArgumentException e) { - LOGGER.error(e); - } - } - return notify; + } + + private void loadConfigurationFromDatabase() { + // TODO(lloydwatkin) Auto-generated method stub + + } + + private void loadConfigurationFromFile() throws IOException { + InputStream confFile = this.getClass().getClassLoader().getResourceAsStream(CONFIGURATION_FILE); + if (confFile != null) { + load(confFile); + LOGGER.info("Loaded " + CONFIGURATION_FILE + " from classpath."); + } else { + File f = new File(CONFIGURATION_FILE); + load(new FileInputStream(f)); + LOGGER.info("Loaded " + CONFIGURATION_FILE + " from working directory."); } + } - public String getServerDomain() { - return getProperty(CONFIGURATION_SERVER_DOMAIN); - } + private void setupCollections() { + adminUsers = getJIDArrayProperty(CONFIGURATION_ADMIN_USERS); + autosubscribeChannels = getJIDArrayProperty(CONFIGURATION_CHANNELS_AUTOSUBSCRIBE); + } - public String getServerChannelsDomain() { - return getProperty(CONFIGURATION_SERVER_CHANNELS_DOMAIN); - } + public Collection getAdminUsers() { + return adminUsers; + } + + public Collection getAutosubscribeChannels() { + return autosubscribeChannels; + } - public String getServerTopicsDomain() { - return getProperty(CONFIGURATION_SERVER_TOPICS_DOMAIN); + public static Configuration getInstance() { + if (null == instance) { + instance = new Configuration(); } + return instance; + } + + public static void reset() { + instance = null; + } + + public String getProperty(String key) { + return conf.getProperty(key); + } + + @Override + public synchronized Object remove(Object key) { + return conf.remove(key); + } + + public void clear() { + conf.clear(); + } + + public String getProperty(String key, String defaultValue) { + return conf.getProperty(key, defaultValue); + } + + public void putProperty(String key, String value) { + conf.put(key, value); + } + + public void load(InputStream inputStream) throws IOException { + conf.load(inputStream); + setupCollections(); + } + + private Collection getStringArrayProperty(String key) { + String prop = getProperty(key); - public boolean getBooleanProperty(final String key, - final boolean defaultValue) { - String value = getProperty(key); - - if (value != null) { - if (value.equalsIgnoreCase("true")) { - return true; - } - if (value.equalsIgnoreCase("false")) { - return false; - } - LOGGER.warn("Invalid boolean property value for " + key + ": " - + value); - } - - return defaultValue; + if (null == prop) { + return Collections.emptyList(); } - public String getComponentPort() { - return this.getProperty(XMPP_PORT, "5347"); + return Arrays.asList(prop.split(ARRAY_PROPERTY_SEPARATOR)); + } + + private Collection getJIDArrayProperty(String key) { + Collection props = getStringArrayProperty(key); + + Collection jids = new ArrayList(props.size()); + + for (String prop : props) { + try { + jids.add(new JID(prop)); + } catch (IllegalArgumentException e) { + LOGGER.error(e); + } } - public String getXmppHost() { - return this.getProperty(XMPP_HOST, "127.0.0.1"); + return jids; + } + + public ArrayList getNotificationsList(String event) { + ArrayList notify = new ArrayList(); + if (!getBooleanProperty(event, false)) { + return notify; + } + String[] users = getProperty(NOTIFICATIONS_SENDTO).split(";"); + JID userJid; + for (String user : users) { + try { + userJid = new JID(user); + notify.add(userJid); + } catch (IllegalArgumentException e) { + LOGGER.error(e); + } } - - public boolean isLocalDomain(String domain) { - return LocalDomainChecker.isLocal(domain, this); + return notify; + } + + public String getServerDomain() { + return getProperty(CONFIGURATION_SERVER_DOMAIN); + } + + public String getServerChannelsDomain() { + return getProperty(CONFIGURATION_SERVER_CHANNELS_DOMAIN); + } + + public String getServerTopicsDomain() { + return getProperty(CONFIGURATION_SERVER_TOPICS_DOMAIN); + } + + public boolean getBooleanProperty(final String key, final boolean defaultValue) { + String value = getProperty(key); + + if (value != null) { + if (value.equalsIgnoreCase("true")) { + return true; + } + if (value.equalsIgnoreCase("false")) { + return false; + } + LOGGER.warn("Invalid boolean property value for " + key + ": " + value); } - - public boolean isLocalNode(String nodeId) { - if (false == nodeId.matches("/user/.+@.+/.+")) { - LOGGER.debug("Node " + nodeId + " has an invalid format"); - throw new IllegalArgumentException(INVALID_NODE); - } - String domain = new JID(nodeId.split("/")[2]).getDomain(); - return isLocalDomain(domain); + + return defaultValue; + } + + public String getComponentPort() { + return this.getProperty(XMPP_PORT, "5347"); + } + + public String getXmppHost() { + return this.getProperty(XMPP_HOST, "127.0.0.1"); + } + + public boolean isLocalDomain(String domain) { + return LocalDomainChecker.isLocal(domain, this); + } + + public boolean isLocalNode(String nodeId) { + if (false == nodeId.matches("/user/.+@.+/.+")) { + LOGGER.debug("Node " + nodeId + " has an invalid format"); + throw new IllegalArgumentException(INVALID_NODE); } - - public boolean isLocalJID(JID jid) { - String domain = jid.getDomain(); - return isLocalDomain(domain); + String domain = new JID(nodeId.split("/")[2]).getDomain(); + return isLocalDomain(domain); + } + + public boolean isLocalJID(JID jid) { + String domain = jid.getDomain(); + return isLocalDomain(domain); + } + + public String getDatabaseConnectionUrl() { + String url = this.getProperty("jdbc.proxool.driver-url"); + String user = this.getProperty("jdbc.user"); + if (null != user) { + url += + "?user=" + this.getProperty("jdbc.user") + "&password=" + + this.getProperty("jdbc.password"); } + return url; + } } diff --git a/src/main/java/org/buddycloud/channelserver/db/DefaultNodeStoreFactoryImpl.java b/src/main/java/org/buddycloud/channelserver/db/DefaultNodeStoreFactoryImpl.java index b73657b9..6ce1b39b 100644 --- a/src/main/java/org/buddycloud/channelserver/db/DefaultNodeStoreFactoryImpl.java +++ b/src/main/java/org/buddycloud/channelserver/db/DefaultNodeStoreFactoryImpl.java @@ -1,9 +1,9 @@ package org.buddycloud.channelserver.db; import java.sql.Connection; -import java.util.Properties; import org.apache.log4j.Logger; +import org.buddycloud.channelserver.Configuration; import org.buddycloud.channelserver.db.exception.NodeStoreException; import org.buddycloud.channelserver.db.jdbc.JDBCNodeStore; import org.buddycloud.channelserver.db.jdbc.dialect.Sql92NodeStoreDialect; @@ -13,9 +13,9 @@ public class DefaultNodeStoreFactoryImpl implements NodeStoreFactory { private static final String CONFIGURATION_JDBC_DIALECT = "jdbc.dialect"; private static final Logger LOGGER = Logger.getLogger(DefaultNodeStoreFactoryImpl.class); - private final Properties configuration; + private final Configuration configuration; - public DefaultNodeStoreFactoryImpl(final Properties configuration) throws NodeStoreException { + public DefaultNodeStoreFactoryImpl(final Configuration configuration) throws NodeStoreException { this.configuration = configuration; String dialectClass = configuration.getProperty(CONFIGURATION_JDBC_DIALECT, Sql92NodeStoreDialect.class.getName()); diff --git a/src/main/java/org/buddycloud/channelserver/db/JDBCConnectionFactory.java b/src/main/java/org/buddycloud/channelserver/db/JDBCConnectionFactory.java index 16b8a5ba..d3ad1ffb 100644 --- a/src/main/java/org/buddycloud/channelserver/db/JDBCConnectionFactory.java +++ b/src/main/java/org/buddycloud/channelserver/db/JDBCConnectionFactory.java @@ -3,21 +3,19 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import java.util.Properties; - +import org.buddycloud.channelserver.Configuration; import org.logicalcobwebs.proxool.ProxoolException; public class JDBCConnectionFactory { - private Properties driverProperties; + private Configuration driverProperties; - public JDBCConnectionFactory(Properties conf) throws ClassNotFoundException, ProxoolException { + public JDBCConnectionFactory(Configuration conf) throws ClassNotFoundException, ProxoolException { Class.forName("org.logicalcobwebs.proxool.ProxoolDriver"); this.driverProperties = conf; } Connection getConnection() throws SQLException { - return DriverManager.getConnection(driverProperties.getProperty("jdbc.proxool.driver-url"), driverProperties.getProperty("jdbc.user"), - driverProperties.getProperty("jdbc.password")); + return DriverManager.getConnection(driverProperties.getDatabaseConnectionUrl()); } } From 8f4e72b2782cf420b7e4225beaa52f5b2c94c467 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 10:34:36 +0100 Subject: [PATCH 02/12] Add a containsKey method, use this --- .../java/org/buddycloud/channelserver/Configuration.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index d3ef5c9a..6d6b7d27 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -249,12 +249,15 @@ public boolean isLocalJID(JID jid) { public String getDatabaseConnectionUrl() { String url = this.getProperty("jdbc.proxool.driver-url"); - String user = this.getProperty("jdbc.user"); - if (null != user) { + if (this.containsKey("jdbc.user")) { url += "?user=" + this.getProperty("jdbc.user") + "&password=" + this.getProperty("jdbc.password"); } return url; } + + public boolean containsKey(Object value) { + return conf.containsKey(value); + } } From 5f3b60296f3a96424a5abe0f343fccee8a0ec4b2 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 10:38:32 +0100 Subject: [PATCH 03/12] Add postgres upgrade-8.sql to add 'configuration' table --- postgres/upgrade-8.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 postgres/upgrade-8.sql diff --git a/postgres/upgrade-8.sql b/postgres/upgrade-8.sql new file mode 100644 index 00000000..fe4edbe0 --- /dev/null +++ b/postgres/upgrade-8.sql @@ -0,0 +1,10 @@ +BEGIN TRANSACTION; + +CREATE TABLE "configuration" ("key" TEXT NOT NULL, + "value" TEXT NOT NULL, + "updated" TIMESTAMP); + +INSERT INTO schema_version (version, "when", description) + VALUES (8, 'now', 'Added configuration table'); + +COMMIT; From 87ea8a0d9cbfb508627820b229d9fe0b5477bde0 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 11:14:45 +0100 Subject: [PATCH 04/12] Load configuration from the database --- .../channelserver/Configuration.java | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index 6d6b7d27..162dfee8 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -4,10 +4,17 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.Properties; import org.apache.log4j.Logger; @@ -15,6 +22,8 @@ import org.xmpp.packet.JID; public class Configuration extends Properties { + + private static final Logger LOGGER = Logger.getLogger(Configuration.class); private static final long serialVersionUID = 1L; @@ -58,6 +67,10 @@ public class Configuration extends Properties { public static final String DATABASE_ENV = "database"; + private static final String JDBC_CONNECTION_STRING = "jdbc.proxool.driver-url"; + private static final String JDBC_PASSWORD = "jdbc.password"; + private static final String JDBC_USER = "jdbc.user"; + private static Configuration instance = null; private Collection adminUsers = new ArrayList(); @@ -73,7 +86,7 @@ private Configuration() { if (null == databaseConnectionString) { loadConfigurationFromFile(); } else { - loadConfigurationFromDatabase(); + loadConfigurationFromDatabase(databaseConnectionString); } } catch (Exception e) { @@ -82,8 +95,26 @@ private Configuration() { } } - private void loadConfigurationFromDatabase() { - // TODO(lloydwatkin) Auto-generated method stub + private void loadConfigurationFromDatabase(String connectionString) throws SQLException { + Connection connection = null; + try { + connection = DriverManager.getConnection(connectionString); + PreparedStatement statement = connection.prepareStatement("SELECT \"key\", \"value\" FROM 'configuration';"); + ResultSet rs = statement.executeQuery(); + while (rs.next()) { + conf.setProperty(rs.getString(1), rs.getString(2)); + } + conf.setProperty(JDBC_CONNECTION_STRING, connectionString); + conf.remove(JDBC_USER); + conf.remove(JDBC_PASSWORD); + } catch (SQLException e) { + LOGGER.error("Could not get configuration from database"); + System.exit(1); + } finally { + if (null != connection) { + connection.close(); + } + } } @@ -248,16 +279,16 @@ public boolean isLocalJID(JID jid) { } public String getDatabaseConnectionUrl() { - String url = this.getProperty("jdbc.proxool.driver-url"); - if (this.containsKey("jdbc.user")) { + String url = this.getProperty(JDBC_CONNECTION_STRING); + if (this.containsKey(JDBC_USER)) { url += - "?user=" + this.getProperty("jdbc.user") + "&password=" - + this.getProperty("jdbc.password"); + "?user=" + this.getProperty(JDBC_USER) + "&password=" + + this.getProperty(JDBC_PASSWORD); } return url; } - + public boolean containsKey(Object value) { return conf.containsKey(value); - } + } } From 3cd0349b2662f699c1eb23c3a77da6ce0e979a1a Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 11:46:58 +0100 Subject: [PATCH 05/12] Move database configuration loader to its own class --- .../channelserver/Configuration.java | 46 ++++++----------- .../utils/configuration/DatabaseLoader.java | 50 +++++++++++++++++++ 2 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index 162dfee8..5f82d2e1 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -19,11 +19,11 @@ import org.apache.log4j.Logger; import org.buddycloud.channelserver.channel.LocalDomainChecker; +import org.buddycloud.channelserver.utils.configuration.DatabaseLoader; import org.xmpp.packet.JID; public class Configuration extends Properties { - private static final Logger LOGGER = Logger.getLogger(Configuration.class); private static final long serialVersionUID = 1L; @@ -65,11 +65,11 @@ public class Configuration extends Properties { public static final String XMPP_HOST = "xmpp.host"; - public static final String DATABASE_ENV = "database"; + public static final String DATABASE_ENV = "DATABASE"; - private static final String JDBC_CONNECTION_STRING = "jdbc.proxool.driver-url"; - private static final String JDBC_PASSWORD = "jdbc.password"; - private static final String JDBC_USER = "jdbc.user"; + public static final String JDBC_CONNECTION_STRING = "jdbc.proxool.driver-url"; + public static final String JDBC_PASSWORD = "jdbc.password"; + public static final String JDBC_USER = "jdbc.user"; private static Configuration instance = null; @@ -86,36 +86,15 @@ private Configuration() { if (null == databaseConnectionString) { loadConfigurationFromFile(); } else { - loadConfigurationFromDatabase(databaseConnectionString); + DatabaseLoader loader = new DatabaseLoader(this, databaseConnectionString); + loader.load(); } } catch (Exception e) { LOGGER.error("Could not load configuration"); System.exit(1); } - } - - private void loadConfigurationFromDatabase(String connectionString) throws SQLException { - Connection connection = null; - try { - connection = DriverManager.getConnection(connectionString); - PreparedStatement statement = connection.prepareStatement("SELECT \"key\", \"value\" FROM 'configuration';"); - ResultSet rs = statement.executeQuery(); - while (rs.next()) { - conf.setProperty(rs.getString(1), rs.getString(2)); - } - conf.setProperty(JDBC_CONNECTION_STRING, connectionString); - conf.remove(JDBC_USER); - conf.remove(JDBC_PASSWORD); - } catch (SQLException e) { - LOGGER.error("Could not get configuration from database"); - System.exit(1); - } finally { - if (null != connection) { - connection.close(); - } - } - + setupCollections(); } private void loadConfigurationFromFile() throws IOException { @@ -177,7 +156,6 @@ public void putProperty(String key, String value) { public void load(InputStream inputStream) throws IOException { conf.load(inputStream); - setupCollections(); } private Collection getStringArrayProperty(String key) { @@ -291,4 +269,12 @@ public String getDatabaseConnectionUrl() { public boolean containsKey(Object value) { return conf.containsKey(value); } + + public Object setProperty(String key, String value) { + return conf.setProperty(key, value); + } + + public void removeKey(String key) { + conf.remove(key); + } } diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java new file mode 100644 index 00000000..73714e2e --- /dev/null +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java @@ -0,0 +1,50 @@ +package org.buddycloud.channelserver.utils.configuration; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.buddycloud.channelserver.Configuration; + +public class DatabaseLoader { + + private static final Logger LOGGER = Logger.getLogger(DatabaseLoader.class); + private Configuration conf; + private String connectionString; + + public DatabaseLoader(Configuration conf, String connectionString) { + this.connectionString = connectionString; + this.conf = conf; + } + + public void load() throws SQLException { + + Connection connection = null; + LOGGER.info("Loading configuration from database"); + try { + connection = DriverManager.getConnection(this.connectionString); + PreparedStatement statement = + connection.prepareStatement("SELECT \"key\", \"value\" FROM \"configuration\";"); + ResultSet rs = statement.executeQuery(); + while (rs.next()) { + this.conf.setProperty(rs.getString(1), rs.getString(2)); + } + this.conf.setProperty(Configuration.JDBC_CONNECTION_STRING, connectionString); + this.conf.removeKey(Configuration.JDBC_USER); + this.conf.removeKey(Configuration.JDBC_PASSWORD); + } catch (SQLException e) { + e.printStackTrace(); + e.getMessage(); + LOGGER.error("Could not get configuration from database"); + System.exit(1); + } finally { + if (null != connection) { + connection.close(); + } + } + } + +} From 5a6b1a6baa1cc5ce3f7d0025e66ef71c18110fc1 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 12:19:38 +0100 Subject: [PATCH 06/12] Shift file configuration loading to its own class --- .../channelserver/Configuration.java | 48 +++++++++---------- .../configuration/ConfigurationException.java | 9 ++++ .../utils/configuration/DatabaseLoader.java | 16 ++++--- .../utils/configuration/FileLoader.java | 43 +++++++++++++++++ .../utils/configuration/Loader.java | 7 +++ 5 files changed, 92 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/buddycloud/channelserver/utils/configuration/ConfigurationException.java create mode 100644 src/main/java/org/buddycloud/channelserver/utils/configuration/FileLoader.java create mode 100644 src/main/java/org/buddycloud/channelserver/utils/configuration/Loader.java diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index 5f82d2e1..2b00bebd 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -4,6 +4,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -19,7 +20,10 @@ import org.apache.log4j.Logger; import org.buddycloud.channelserver.channel.LocalDomainChecker; +import org.buddycloud.channelserver.utils.configuration.ConfigurationException; import org.buddycloud.channelserver.utils.configuration.DatabaseLoader; +import org.buddycloud.channelserver.utils.configuration.FileLoader; +import org.buddycloud.channelserver.utils.configuration.Loader; import org.xmpp.packet.JID; public class Configuration extends Properties { @@ -56,9 +60,7 @@ public class Configuration extends Properties { public static final String NOTIFICATIONS_SENDTO = "notifications.sendTo"; public static final String NOTIFICATIONS_CONNECTED = "notifications.connected"; - - private static final String CONFIGURATION_FILE = "configuration.properties"; - + public static final String PURGE_REMOTE_ON_START = "sync.purge-on-start"; public static final String XMPP_PORT = "xmpp.port"; @@ -78,47 +80,44 @@ public class Configuration extends Properties { private Properties conf; + private boolean collectionsSetup = false; + private Configuration() { try { conf = new Properties(); String databaseConnectionString = System.getenv(DATABASE_ENV); + Loader loader = null; if (null == databaseConnectionString) { - loadConfigurationFromFile(); + loader = new FileLoader(this); } else { - DatabaseLoader loader = new DatabaseLoader(this, databaseConnectionString); - loader.load(); + loader = new DatabaseLoader(this, databaseConnectionString); } + loader.load(); - } catch (Exception e) { - LOGGER.error("Could not load configuration"); + } catch (ConfigurationException e) { + LOGGER.error(e.getMessage()); System.exit(1); } setupCollections(); } - private void loadConfigurationFromFile() throws IOException { - InputStream confFile = this.getClass().getClassLoader().getResourceAsStream(CONFIGURATION_FILE); - if (confFile != null) { - load(confFile); - LOGGER.info("Loaded " + CONFIGURATION_FILE + " from classpath."); - } else { - File f = new File(CONFIGURATION_FILE); - load(new FileInputStream(f)); - LOGGER.info("Loaded " + CONFIGURATION_FILE + " from working directory."); - } - } - private void setupCollections() { + if (true == collectionsSetup) { + return; + } adminUsers = getJIDArrayProperty(CONFIGURATION_ADMIN_USERS); autosubscribeChannels = getJIDArrayProperty(CONFIGURATION_CHANNELS_AUTOSUBSCRIBE); + collectionsSetup = true; } public Collection getAdminUsers() { + setupCollections(); return adminUsers; } public Collection getAutosubscribeChannels() { + setupCollections(); return autosubscribeChannels; } @@ -154,10 +153,6 @@ public void putProperty(String key, String value) { conf.put(key, value); } - public void load(InputStream inputStream) throws IOException { - conf.load(inputStream); - } - private Collection getStringArrayProperty(String key) { String prop = getProperty(key); @@ -277,4 +272,9 @@ public Object setProperty(String key, String value) { public void removeKey(String key) { conf.remove(key); } + + public void load(InputStream stream) throws IOException { + collectionsSetup = false; + conf.load(stream); + } } diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/ConfigurationException.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/ConfigurationException.java new file mode 100644 index 00000000..a71c9287 --- /dev/null +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/ConfigurationException.java @@ -0,0 +1,9 @@ +package org.buddycloud.channelserver.utils.configuration; + +public class ConfigurationException extends Exception { + + public ConfigurationException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java index 73714e2e..cba4b6c6 100644 --- a/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java @@ -9,7 +9,7 @@ import org.apache.log4j.Logger; import org.buddycloud.channelserver.Configuration; -public class DatabaseLoader { +public class DatabaseLoader implements Loader { private static final Logger LOGGER = Logger.getLogger(DatabaseLoader.class); private Configuration conf; @@ -20,7 +20,7 @@ public DatabaseLoader(Configuration conf, String connectionString) { this.conf = conf; } - public void load() throws SQLException { + public void load() throws ConfigurationException { Connection connection = null; LOGGER.info("Loading configuration from database"); @@ -36,13 +36,15 @@ public void load() throws SQLException { this.conf.removeKey(Configuration.JDBC_USER); this.conf.removeKey(Configuration.JDBC_PASSWORD); } catch (SQLException e) { - e.printStackTrace(); - e.getMessage(); - LOGGER.error("Could not get configuration from database"); - System.exit(1); + throw new ConfigurationException("Could not get configuration from database"); } finally { - if (null != connection) { + if (null == connection) { + return; + } + try { connection.close(); + } catch (SQLException e) { + throw new ConfigurationException("Could not get configuration from database"); } } } diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/FileLoader.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/FileLoader.java new file mode 100644 index 00000000..48d51254 --- /dev/null +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/FileLoader.java @@ -0,0 +1,43 @@ +package org.buddycloud.channelserver.utils.configuration; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.log4j.Logger; +import org.buddycloud.channelserver.Configuration; + +public class FileLoader implements Loader { + + private static final Logger LOGGER = Logger.getLogger(FileLoader.class); + + private static final String CONFIGURATION_FILE = "configuration.properties"; + + private Configuration conf; + + public FileLoader(Configuration conf) { + this.conf = conf; + } + + public void load() throws ConfigurationException { + InputStream confFile = this.getClass().getClassLoader().getResourceAsStream(CONFIGURATION_FILE); + try { + if (confFile != null) { + readFile(confFile); + LOGGER.info("Loaded " + CONFIGURATION_FILE + " from classpath."); + } else { + File f = new File(CONFIGURATION_FILE); + readFile(new FileInputStream(f)); + LOGGER.info("Loaded " + CONFIGURATION_FILE + " from working directory."); + } + } catch (IOException e) { + throw new ConfigurationException("Could not load configuraton from file " + CONFIGURATION_FILE); + } + } + + private void readFile(InputStream inputStream) throws IOException { + this.conf.load(inputStream); + } + +} diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/Loader.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/Loader.java new file mode 100644 index 00000000..f3c55f8e --- /dev/null +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/Loader.java @@ -0,0 +1,7 @@ +package org.buddycloud.channelserver.utils.configuration; + +public interface Loader { + + public void load() throws ConfigurationException; + +} From 6d0b487789dd1dad6f686600a689a2dc6192ae27 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 14:28:49 +0100 Subject: [PATCH 07/12] Add details about database configuration to the README.md file --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 817bb3ad..ecab7757 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,16 @@ Please see [the example configuration file](https://github.com/buddycloud/buddyc | sync.purge-on-start | false | | Purge remote data on server start | | users.presence.persist | false | | If **true** then user presence status is stored in the database rather than in memory | +### Database based configuration + +If you prefer to load your configuration from a database then this is possible. Simply load all your configuration key/values into the "configuration" table within the database (__note:__ **jdbc.proxool.driver-url**, **jdbc.user**, and **jdbc.password** values will be ignored). When starting the server set an evironment variable of __DATABASE__ to the Postgres connection string which will connect to your database. For example: + +``` +DATABASE="jdbc:postgresql://localhost:5432/buddycloud-server?user=buddycloud&password=tellnoone" +``` + +The server will then use the database values to configure itself. + ## Additional content-type plugins The buddycloud server supports validation of custom content types by means of a plugin system. By default the buddycloud server supports Atom content. Additional content types can be supported by creating an appropriate validator and packaging it as a plugin. From eb9c74084eddc8525f98e73fb8e5933873144902 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 14:47:13 +0100 Subject: [PATCH 08/12] Add an initial docker setup --- .gitignore | 1 + Dockerfile | 18 ++++++++++++++++++ src/main/resources/log4j.properties | 17 +++++++++++++++++ src/main/resources/start.sh | 9 +++++++++ 4 files changed, 45 insertions(+) create mode 100644 Dockerfile create mode 100644 src/main/resources/log4j.properties create mode 100755 src/main/resources/start.sh diff --git a/.gitignore b/.gitignore index ac99b3ac..84e7d1f1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ logs *.BASE.* *.LOCAL.* *.REMOTE.* +!src/main/resources/log4j.properties diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..977f076c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +################################################################################ +# Build a dockerfile for buddycloud-server-java +# Based on ubuntu +################################################################################ + +FROM dockerfile/java + +EXPOSE 3000 + +RUN apt-get update +RUN apt-get upgrade -y + +RUN git clone https://github.com/buddycloud/buddycloud-server-java.git +RUN cd buddycloud-server-java && mvn package +ADD ./src/main/resources/log4j.properties . +ADD ./src/main/resources/start.sh . + +CMD /bin/bash start.sh \ No newline at end of file diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 00000000..aa1bd3cb --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,17 @@ +log4j.rootLogger=DEBUG, SYSLOG + +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n + +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +#log4j.appender.FILE=org.apache.log4j.AsyncAppender +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n +log4j.appender.FILE.File=/var/log/buddycloud-server-java.log + +log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender +log4j.appender.SYSLOG.syslogHost=127.0.0.1 +log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout +log4j.appender.SYSLOG.layout.ConversionPattern=%-5p %t: %c{1} - %m +log4j.appender.SYSLOG.Facility=USER diff --git a/src/main/resources/start.sh b/src/main/resources/start.sh new file mode 100755 index 00000000..5eac4a66 --- /dev/null +++ b/src/main/resources/start.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +OPTS="" + +if [ -z "$DATABASE" ]; then + OPTS=" $OPTS -DDATABASE=\"$DATABASE\"" +fi + +java $OPTS -jar target/channelserver-jar-with-dependencies.jar \ No newline at end of file From 3e47302cbd44ddf592027c6eb2a8b939b4258164 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 14:54:15 +0100 Subject: [PATCH 09/12] Add maintainer details --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 977f076c..a19bba92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ FROM dockerfile/java -EXPOSE 3000 +MAINTAINER Lloyd Watkin RUN apt-get update RUN apt-get upgrade -y From 3a28b1371f464d47ce8b9723bb74ee145dd26d11 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 14:54:25 +0100 Subject: [PATCH 10/12] Install maven --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index a19bba92..720e2444 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,7 @@ MAINTAINER Lloyd Watkin RUN apt-get update RUN apt-get upgrade -y +RUN apt-get install -y maven RUN git clone https://github.com/buddycloud/buddycloud-server-java.git RUN cd buddycloud-server-java && mvn package From f9f02bee1071dc0126306c267a2e42284731ae03 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 16:05:59 +0100 Subject: [PATCH 11/12] Update docker implementation --- Dockerfile | 10 +++++----- {src/main/resources => contrib/docker}/start.sh | 3 ++- .../org/buddycloud/channelserver/Configuration.java | 8 +------- .../utils/configuration/DatabaseLoader.java | 2 ++ 4 files changed, 10 insertions(+), 13 deletions(-) rename {src/main/resources => contrib/docker}/start.sh (69%) diff --git a/Dockerfile b/Dockerfile index 720e2444..69ed4be2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Based on ubuntu ################################################################################ -FROM dockerfile/java +FROM dockerfile/java:openjdk-7-jdk MAINTAINER Lloyd Watkin @@ -13,7 +13,7 @@ RUN apt-get install -y maven RUN git clone https://github.com/buddycloud/buddycloud-server-java.git RUN cd buddycloud-server-java && mvn package -ADD ./src/main/resources/log4j.properties . -ADD ./src/main/resources/start.sh . - -CMD /bin/bash start.sh \ No newline at end of file +ADD src/main/resources/log4j.properties /data/buddycloud-server-java/ +ADD contrib/docker/start.sh /data/ +RUN chmod +x start.sh +CMD ./start.sh \ No newline at end of file diff --git a/src/main/resources/start.sh b/contrib/docker/start.sh similarity index 69% rename from src/main/resources/start.sh rename to contrib/docker/start.sh index 5eac4a66..916bc6b6 100755 --- a/src/main/resources/start.sh +++ b/contrib/docker/start.sh @@ -2,8 +2,9 @@ OPTS="" -if [ -z "$DATABASE" ]; then +if [ "$DATABASE" != "" ]; then OPTS=" $OPTS -DDATABASE=\"$DATABASE\"" fi +cd buddycloud-server-java java $OPTS -jar target/channelserver-jar-with-dependencies.jar \ No newline at end of file diff --git a/src/main/java/org/buddycloud/channelserver/Configuration.java b/src/main/java/org/buddycloud/channelserver/Configuration.java index 2b00bebd..1708685d 100644 --- a/src/main/java/org/buddycloud/channelserver/Configuration.java +++ b/src/main/java/org/buddycloud/channelserver/Configuration.java @@ -213,13 +213,7 @@ public boolean getBooleanProperty(final String key, final boolean defaultValue) String value = getProperty(key); if (value != null) { - if (value.equalsIgnoreCase("true")) { - return true; - } - if (value.equalsIgnoreCase("false")) { - return false; - } - LOGGER.warn("Invalid boolean property value for " + key + ": " + value); + return Boolean.valueOf(value); } return defaultValue; diff --git a/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java index cba4b6c6..da7a2eed 100644 --- a/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java +++ b/src/main/java/org/buddycloud/channelserver/utils/configuration/DatabaseLoader.java @@ -36,6 +36,7 @@ public void load() throws ConfigurationException { this.conf.removeKey(Configuration.JDBC_USER); this.conf.removeKey(Configuration.JDBC_PASSWORD); } catch (SQLException e) { + LOGGER.error(e); throw new ConfigurationException("Could not get configuration from database"); } finally { if (null == connection) { @@ -44,6 +45,7 @@ public void load() throws ConfigurationException { try { connection.close(); } catch (SQLException e) { + LOGGER.error(e); throw new ConfigurationException("Could not get configuration from database"); } } From 4d8d711caa0408ebbda5584fd82717c0e8d16bd2 Mon Sep 17 00:00:00 2001 From: Lloyd Watkin Date: Thu, 16 Oct 2014 16:15:05 +0100 Subject: [PATCH 12/12] Add note about ignoreing the configuration.properties file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ecab7757..8929173c 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ If you prefer to load your configuration from a database then this is possible. DATABASE="jdbc:postgresql://localhost:5432/buddycloud-server?user=buddycloud&password=tellnoone" ``` -The server will then use the database values to configure itself. +The server will then use the database values to configure itself, the `configuration.properties` file will be ignored. ## Additional content-type plugins The buddycloud server supports validation of custom content types by means of a plugin system. By default the buddycloud server supports Atom content. Additional content types can be supported by creating an appropriate validator and packaging it as a plugin.