Skip to content
Permalink
Browse files

Use pax-jdbc-config to set up the PostgreSQL datasource

  • Loading branch information
steinarb committed Oct 31, 2019
1 parent d93453a commit cfbe2d1bb41c31220cb2080b3cd185180b17ccd7
@@ -101,7 +101,7 @@ Procedure:
2. Install the application
#+BEGIN_EXAMPLE
feature:repo-add mvn:no.priv.bang.sonar.sonar-collector/sonar-collector-webhook/LATEST/xml/features
feature:install sonar-collector-webhook
feature:install sonar-collector-webhook-with-postgresql
#+END_EXAMPLE

(the application has been installed into maven central, which is a repository that is builtin to karaf)
@@ -119,10 +119,13 @@ Procedure:
The password is "karaf" (without the quotes)
2. In the karaf command shell, create configuration for the JDBC connection:
#+BEGIN_EXAMPLE
config:edit no.priv.bang.sonar.collector.webhook.SonarCollectorServlet
config:property-set sonar.collector.jdbc.url "jdbc:postgresql://lorenzo.hjemme.lan/sonarcollector"
config:property-set sonar.collector.jdbc.user "karaf"
config:property-set sonar.collector.jdbc.password "karaf"
config:edit org.ops4j.datasource-sonar-collector
config:property-set osgi.jdbc.driver.name "PostgreSQL JDBC Driver"
config:property-set dataSourceName "jdbc/sonar-collector"
config:property-set url "jdbc:postgresql://lorenzo.hjemme.lan/sonarcollector"
config:property-set user "karaf"
config:property-set password "karaf"
config:property-set org.apache.karaf.features.configKey "org.ops4j.datasource-sonar-collector"
config:update
#+END_EXAMPLE
(this assumes the username/password combination karaf/karaf, it is recommended to use a different password in a real setting with PostgreSQL accepting network connections)
@@ -159,6 +162,30 @@ Procedure, do the following, logged in as root on the server:
#+BEGIN_EXAMPLE
systemctl restart postgresql
#+END_EXAMPLE
**** Using a different database than PostgreSQL

/WARNING/! This is not regularily tested (i.e. won't be tested before releases) and I don't plan to actually use sonar-collector with anything except PostgreSQL myself.

To use JDBC against a RDBMS other than PostgreSQL, do the following from the karaf console command line (derby in-memory database used in the examples):
1. Load the component providing the DataSourceFactory OSGi service:
#+BEGIN_EXAMPLE
feature:install pax-jdbc-derby
#+END_EXAMPLE
2. Add karaf configuration selecting the correct DataSourceFactory and JDBC connection info (url, user and password):
#+BEGIN_EXAMPLE
config:edit org.ops4j.datasource-sonar-collector
config:property-set osgi.jdbc.driver.name "PostgreSQL JDBC Driver"
config:property-set dataSourceName "jdbc/sonar-collector"
config:property-set url "jdbc:derby:data/example/derby;create=true"
config:property-set osgi.jdbc.driver.name derby
config:property-set org.apache.karaf.features.configKey "org.ops4j.datasource-sonar-collector"
config:update
#+END_EXAMPLE
3. Load sonar-collector using a feature that doesn't unnecessarily pull in the PostgreSQL DataSourceFactory:
#+BEGIN_EXAMPLE
feature:repo-add mvn:no.priv.bang.sonar.sonar-collector/sonar-collector-webhook/LATEST/xml/features
feature:install sonar-collector-webhook-with-jdbc
#+END_EXAMPLE

*** Add a webhook to Sonar

@@ -36,6 +36,7 @@
<pax.jdbc.version>1.0.1</pax.jdbc.version>
<liquibase.version>3.5.3</liquibase.version>
<liquibase-slf4j.version>2.0.0</liquibase-slf4j.version>
<postgresql.version>42.2.8</postgresql.version>
<jackson.version>2.9.10</jackson.version>
<jackson.databind.version>2.9.10.1</jackson.databind.version>
<osgi-service-adaptors.version>1.0.1</osgi-service-adaptors.version>
@@ -183,7 +184,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.8</version>
<version>${postgresql.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
@@ -96,6 +96,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>no.priv.bang.karaf</groupId>
@@ -1,11 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<features>
<features xmlns="http://karaf.apache.org/xmlns/features/v1.5.0">
<repository>mvn:org.postgresql/postgresql/${postgresql.version}/xml/features</repository>
<repository>mvn:no.priv.bang.osgi.service.adapters/service-adapters-karaf/${osgi-service-adaptors.version}/xml/features</repository>
<feature name="sonar-collector-postgresql-jdbc-provider" version="${project.version}">
<config name="org.ops4j.datasource-sonar-collector">
osgi.jdbc.driver.name=PostgreSQL JDBC Driver
dataSourceName=jdbc/sonar-collector
url=jdbc:postgresql:///sonar-collector
user=karaf
password=karaf
</config>
<capability>
osgi.service;objectClass=javax.sql.DataSource;effective:=active;osgi.jndi.service.name=jdbc/sonar-collector
</capability>
<feature>jdbc</feature>
</feature>
<feature name="${karaf-feature-name}">
<capability>osgi.service;effective:=active;objectClass=org.osgi.service.jdbc.DataSourceFactory</capability>
<feature>adapter-for-osgi-logservice</feature>
<feature>adapters-for-osgi-jdbc-services</feature>
<feature>pax-http-whiteboard</feature>
<feature>liquibase-core</feature>
</feature>

<feature name="${karaf-feature-name}-with-jdbc">
<feature>sonar-collector-postgresql-jdbc-provider</feature>
<feature>${karaf-feature-name}</feature>
</feature>

<feature name="${karaf-feature-name}-with-postgresql">
<feature>postgresql</feature>
<feature>${karaf-feature-name}-with-jdbc</feature>
</feature>
</features>

This file was deleted.

@@ -21,7 +21,6 @@
import java.util.Map;
import java.util.Properties;

import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.log.LogService;

/***
@@ -32,9 +31,6 @@
*
*/
public class SonarCollectorConfiguration {
static final String SONARCOLLECTOR_JDBC_URL = "sonar.collector.jdbc.url";
static final String SONARCOLLECTOR_JDBC_USER = "sonar.collector.jdbc.user";
static final String SONARCOLLECTOR_JDBC_PASS = "sonar.collector.jdbc.password";
static final String SONAR_MEASURES_COMPONENTS_METRIC_KEYS = "sonar.measures.components.metricKeys";
private final Properties applicationProperties = new Properties();
private Map<String, Object> injectedconfig = Collections.emptyMap();
@@ -60,22 +56,6 @@ public void setConfig(Map<String, Object> config) {
}
}

/**
* Retrive the settings necessary to open a JDBC connection from
* the configuration. First the injected configuration service is
* used, then the system properties, and finally the embedded application.properties
* file is used.
*
* @return a properties object that can be sent to {@link DataSourceFactory#createDataSource(Properties)}
*/
public Properties getJdbcConnectionProperties() {
Properties properties = new Properties();
setJdbcUrlIfNotNull(properties);
setPropertyIfNotNull(properties, DataSourceFactory.JDBC_USER, SonarCollectorConfiguration.SONARCOLLECTOR_JDBC_USER);
setPropertyIfNotNull(properties, DataSourceFactory.JDBC_PASSWORD, SonarCollectorConfiguration.SONARCOLLECTOR_JDBC_PASS);
return properties;
}

/**
* Retrieve the list of metrics that should be retrieved from Sonar
* First the injected config is used to find the values, and if nothing
@@ -91,39 +71,11 @@ public Properties getJdbcConnectionProperties() {
return ((String) metricKeysFromKarafConfig).split(",");
}

return System.getProperty(SONAR_MEASURES_COMPONENTS_METRIC_KEYS, applicationProperties.getProperty(SONAR_MEASURES_COMPONENTS_METRIC_KEYS)).split(",");
}

public String getJdbcUrl() {
// Settings made in karaf configuration takes precedence
Object jdbcUrlFromKarafConfig = injectedconfig.get(SONARCOLLECTOR_JDBC_URL);
if (jdbcUrlFromKarafConfig != null) {
return (String) jdbcUrlFromKarafConfig;
String metricKeys = System.getProperty(SONAR_MEASURES_COMPONENTS_METRIC_KEYS, applicationProperties.getProperty(SONAR_MEASURES_COMPONENTS_METRIC_KEYS));
if (metricKeys != null) {
return metricKeys.split(",");
}

// Fallback to system property which in turn falls back to application.properties
return System.getProperty(SONARCOLLECTOR_JDBC_URL, applicationProperties.getProperty(SONARCOLLECTOR_JDBC_URL));
}

private void setJdbcUrlIfNotNull(Properties properties) {
String jdbcUrl = getJdbcUrl();
if (jdbcUrl != null) {
properties.setProperty(DataSourceFactory.JDBC_URL, jdbcUrl);
}
}

private void setPropertyIfNotNull(Properties properties, String targetPropertyName, String sourcePropertyName) {
// Settings made in karaf configuration takes precedence
Object valueFromKarafConfig = injectedconfig.get(sourcePropertyName);
if (valueFromKarafConfig != null) {
properties.setProperty(targetPropertyName, (String) valueFromKarafConfig);
return;
}

// Fallback to system property which in turn falls back to application.properties
String value = System.getProperty(sourcePropertyName, applicationProperties.getProperty(sourcePropertyName));
if (value != null) {
properties.setProperty(targetPropertyName, value);
}
return new String[0];
}
}
@@ -41,7 +41,6 @@
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.log.LogService;

import com.fasterxml.jackson.databind.JsonNode;
@@ -52,7 +51,6 @@
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ClassLoaderResourceAccessor;
import no.priv.bang.osgi.service.adapters.jdbc.DataSourceAdapter;
import no.priv.bang.osgi.service.adapters.jdbc.DataSourceFactoryAdapter;
import no.priv.bang.osgi.service.adapters.logservice.LogServiceAdapter;

@Component(service={Servlet.class}, property={"alias=/sonar-collector", "configurationPid=no.priv.bang.sonar.sonar-collector-webhook"} )
@@ -69,13 +67,12 @@
private final URLConnectionFactory factory;
static final ObjectMapper mapper = new ObjectMapper();
final DataSourceAdapter dataSource = new DataSourceAdapter();
private final DataSourceFactoryAdapter dataSourceFactory = new DataSourceFactoryAdapter();
private final LogServiceAdapter logservice = new LogServiceAdapter();
final SonarCollectorConfiguration configuration = new SonarCollectorConfiguration(logservice);

@Reference
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.dataSourceFactory.setFactory(dataSourceFactory);
@Reference(target = "(osgi.jndi.service.name=jdbc/sonar-collector)")
public void setDataSource(DataSource ds) {
this.dataSource.setDatasource(ds);
}

@Reference
@@ -86,19 +83,7 @@ public void setLogservice(LogService logservice) {
@Activate
public void activate(Map<String, Object> config) {
configuration.setConfig(config);
DataSource db = connectDataSource(dataSourceFactory);
createSchemaWithLiquibase(db);
dataSource.setDatasource(db);
}

private DataSource connectDataSource(DataSourceFactory dataSourceFactory) {
Properties properties = configuration.getJdbcConnectionProperties();
try {
return dataSourceFactory.createDataSource(properties);
} catch (SQLException e) {
logservice.log(LogService.LOG_ERROR, "Sonar Collector servlet unable to connect to the database", e);
return NullDataSource.getInstance(); // Return an object that can be safely used in try-with-resource
}
createSchemaWithLiquibase(dataSource);
}

private void createSchemaWithLiquibase(DataSource db) {

0 comments on commit cfbe2d1

Please sign in to comment.
You can’t perform that action at this time.