Copy Spring Boot Property Sources into System Properties

Spring Boot is unique in that property values are accessed through Spring’s Environment abstraction. However, certain libraries require properties to be accessible through the System.getProperty(...) convention. Adding a custom factory around the @PropertySource annotation to force properties into the system context is a good solution, however, it might not be the most robust. Anything that might get bootstrapped during the Spring initialization process before the property sources are loaded from the annotation might be misconfigured based on properties that haven’t loaded yet.

To prevent this from happening, a application listener can be configured to listen for the ApplicationEnvironmentPreparedEvent then load properties into the system context before much else has occurred. This listener should be used in conjunction with the system property spring.config.location to set the location of properties to load instead of the @PropertySource annotation. For more information on external configuration, see the Spring Documentation.

The Java and Kotlin examples below demo this implementation.

Java Version

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
      SpringApplication springApplication = new SpringApplication(Application.class);
      springApplication.addListener(new SystemPropertiesSetterEventListener());
      springApplication.run(args);
  }

  private static class SystemPropertiesSetterEventListener
      implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
      event.getEnvironment().getPropertySources().forEach(ps -> {
        if (ps instanceof MapPropertySource) {
          MapPropertySource mps = (MapPropertySource) ps;
          mps.getSource().forEach((key, value) -> System.getProperties().putIfAbsent(key, value.toString()));
        }
      });
    }
  }
}

Kotlin Version

@SpringBootApplication
class Application

fun main(args: Array<String>) {
  runApplication<Application>(args = *args, init = {
    this.addListeners(SystemPropertiesSetterEventListener())
  })
}

class SystemPropertiesSetterEventListener :
    ApplicationListener<ApplicationEnvironmentPreparedEvent> {
  override fun onApplicationEvent(event: ApplicationEnvironmentPreparedEvent) {
    event.environment.propertySources.forEach { ps ->
      if (ps is MapPropertySource) {
        ps.source.forEach {
          System.getProperties().putIfAbsent(it.key, it.value.toString())
        }
      }
    }
  }
}

Using Sonarqube with Kotlin

The state of kotlin and sonarqube

There currently is no offical plugin for sonarqube to support kotlin. In the meantime, the detekt can be used to analyze kotlin projects. Please double check that this is still the case before continuing.

Getting a local Sonarqube running for testing

Setting up Sonarqube via docker with their official image and adding the detekt plugin. The lazy way without a dockerfile:

docker pull sonarqube:<version>
docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube:<verson>
docker exec -it sonarqube bash
wget https://github.com/arturbosch/sonar-kotlin/releases/download/0.4.2/sonar-kotlin-0.4.1.jar
chown sonarqube:sonarqube sonar-kotlin-0.4.1.jar
mv sonar-kotlin-0.4.1.jar /opt/sonarqube/extensions/plugins/
docker restart sonarqube

Setting up configuration via gradle

Added changes needed to root build.gradle file Specific notes: 1. This is a multiproject example, if you have just one project just remove the configure(subjects) wrapping 2. Get a copy of the detekt.yml by running ./gradlew detektGenerateConfig or by copying default-detekt-config.yml. 3. Jacoco is for code coverage

buildscript {
  ext.detektVersion = '1.0.0.RC7'
  dependencies {
    classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2'
    classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detektVersion"
  }
}

apply plugin: 'org.sonarqube'
apply plugin: 'io.gitlab.arturbosch.detekt'

detekt {
  version = $detektVersion
  defaultProfile {
    input = "$projectDir"
    config = "$project.rootDir/detekt.yml" // if you'd like to override the default rules
  }
}

configure(subprojects) { project ->
  apply plugin: 'jacoco'
  jacoco {
    toolVersion = '0.7.5.201505241946'
    reportsDir = file("$buildDir/jacocoReports")
  }

  sonarqube {
    properties {
      property "detekt.sonar.kotlin.config.path", "$project.rootDir/detekt.yml"
      property "detekt.sonar.kotlin.filters", ".*/test/.*,.*/resources/.*,.*/build/.*,.*/target/.*"
    }
  }
}

Side notes

Detekt filtering, make sure this is correct or you’ll get 0 kotlin files were analyzed. Examples of what might be filtered for the following .*/test/.*,.*/resources/.*,.*/build/.*,.*/target/.*:

/build/project-name/src/main/kotlin/com/exmaple/App.kt
/project-name/build/lib/app.jar
/project-name/src/test/kotlin/com/example/AppTest.kt
/project-name/build/target/App.kt
/project-name/target/App.kt
/project-name/src/main/resources/App.kt

How to fix Synology Hyper Backup Explorer Insufficient Privileges Error

A quick guide to fix the following error message given in Hyper Backup Explorer when trying to access a usb backup.

synology-hyper-backup-explorer-insufficient-privileges

Insufficient privileges to access some subfolders under the destination shared folder. Please contact the destination administrator for assistance.

The application actually outputs the error to a log under the running directory called HyperBackupExplorer.log and contains the following

2017-06-03 01:28:57 PM (5775) [debug] target_manager.cpp:186 synobkpinfo.db [/media/user/drive/diskstation_backup/synobkpinfo.db] access failed Permission denied
2017-06-03 01:28:57 PM (5775) [debug] target_manager.cpp:186 synobkpinfo.db [/media/user/drive/diskstation_backup/synobkpinfo.db] access failed Permission denied
2017-06-03 01:28:57 PM backuptargetimpl.cpp:73 get target failed

A simple fix for this is to change the file permissions for the database file with the following command (note please change the media directory path with the correct mount path for the drive):

cd /media/user/drive/diskstation_backup/
sudo chmod o+r synobkpinfo.db

Ubuntu 17.04 Install Nvidia Drivers

Looking for Ubuntu 16.04/16.10?

Quick guide on how to install nvidia drivers on a fresh install of Ubuntu 17.04 with full disk encryption. The following steps were tested with a GTX 1070 and Intel HD Graphics 530 integrated graphics.

  • Boot and install via normal usb ubuntu installer
  • After installation reboot and login
  • Run update system software via terminal
sudo apt-get update && sudo apt-get upgrade
  • Reboot system
  • Switch to tty1 by ctl-alt-f1 and login
  • Stop x
sudo /etc/init.d/lightdm stop
  • Remove the default nouveau drivers:
sudo apt-get --purge remove xserver-xorg-video-nouveau
  • Add nvidia ppa and install correct driver version replacing nvidia-381 with whatever version you’d like
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-381
sudo nvidia-xconfig
  • Edit file /etc/default/grub with your favorite editor
  • Edit line 11
From: GRUB_CMDLINE_LINUX_DEFAULT="quiet nosplash noplymouth"
To:   GRUB_CMDLINE_LINUX_DEFAULT="quiet"
  • Uncomment line 25 and change to your monitor’s resolution (for aesthetics)
GRUB_GFXMODE=2560x1440
  • Then update grub and reboot
update-grub
reboot

Note: the first first booting after these changes might only show a black screen, just type in the encryption password and enter and it should login. This seems to only happen the first time.

Ubuntu 16.04 Install Nvidia Drivers

Looking for Ubuntu 17.04?

Quick guide on how to install nvidia drivers on Ubuntu 16.04 (tested with 16.04 and 16.04.1 installs with a GTX 1070 and Intel HD Graphics 530 integrated graphics).

  • Disable PCI graphics in the bios or switch to automatic
  • Shutdown and plug in the display output to integrated graphics
  • Boot and install via normal usb ubuntu installer
  • After installation reboot
  • Run update system software via terminal
sudo apt-get update && sudo apt-get upgrade
  • Reboot system
  • Switch to tty1 by ctl-alt-f1 and login
  • Stop x
sudo /etc/init.d/lightdm stop
  • Remove the default nouveau drivers [1]:
sudo apt-get --purge remove xserver-xorg-video-nouveau
  • Add nvidia ppa and install correct driver version replacing nvidia-367 with whatever version you’d like
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-367
sudo nvidia-xconfig
  • Reboot and enable the PCI graphics back in the bios
  • Shutdown and switch display output back to the graphics card

Special notes about full disk encryption [2],[3],[4],[5]

  1. After reboot, only see a purple screen
  2. After reboot, only see a black screen
  3. Might see the decrypt splash but the keyboard is unresponsive

I had best results editing the grub config with the following via recovery mode

  • Reboot and hold down shift while booting to bring up the grub menu
  • Select advanced options for ubuntu and select ubuntu with recovery mode
  • Add networking to get the file system in read/write
  • Then add root and press enter for maintenance mode
  • Edit file /etc/default/grub with your favorite editor
  • Edit line to: GRUB_CMDLINE_LINUX_DEFAULT="quiet nosplash noplymouth"
  • Add line: GRUB_GFXPAYLOAD_LINUX=keep
  • Add line: GRUB_GFXMODE=2560x1440
  • Then update grub and reboot
update-grub
reboot

Completed grub file looking simpler to:

# /etc/default/grub
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0
GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet nosplash noplymouth"
GRUB_CMDLINE_LINUX=""
GRUB_GFXPAYLOAD_LINUX=keep

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
GRUB_GFXMODE=2560x1440

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

[1] https://help.ubuntu.com/community/BinaryDriverHowto/Nvidia#RemovingNouveau.28advanced.2Fexpert_users.29

[2] http://askubuntu.com/questions/689064/cant-enter-password-for-luks-disk-encryption-after-nvidia-drivers-installed

[3] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1359689/comments/73

[4] https://bugs.launchpad.net/ubuntu/+source/plymouth/+bug/1386005/comments/72

[5] http://askubuntu.com/questions/362722/how-to-fix-plymouth-splash-screen-in-all-ubuntu-releases