Referencing to values in typesafe config - config

I have a config file:
app {
system {
action-type = "REST"
}
}
roles = [${app.system.action-type} "notifier"]
I want roles to have a value [ RESTnotifier ], but this approach gives me an exception. Any suggestions?
com.typesafe.config.ConfigException$NotResolved: need to Config#resolve() each config before using it, see the API docs for Config#resolve()

You need to explicitly call resolve on the Config instance if you are going to be using replacements in the config. A quick example showing this:
import com.typesafe.config.ConfigFactory
import collection.JavaConversions._
object ConfigExample extends App{
val cfgString = """
app {
system {
action-type = "REST"
}
}
roles = [${app.system.action-type}"notifier"]
"""
val cfg = ConfigFactory.parseString(cfgString).resolve()
println(cfg.getStringList("roles").toList)
}
Note the explicit call to resolve. That should fix your issue.

Related

How to properly create and connect to database with Kotlin Exposed?

I did check the similar question here, but it didn't work as expected for me, I still need to reconnect to the created database and I'm not sure how or even if I can avoid that.
Here is my code:
hikari.properties:
jdbcUrl=jdbc:mariadb://localhost:3306/
driverClassName=org.mariadb.jdbc.Driver
username=root
dataSource.databaseName=DBNAME //this doesn't seem to do much, I'm getting the same behavior with or without it
fun initDB() {
val config = HikariConfig("/hikari.properties")
val ds = HikariDataSource(config)
transaction(connect(ds)) {
SchemaUtils.createDatabase("DBNAME")
}
config.jdbcUrl = "jdbc:mariadb://localhost:3306/DBNAME"
//ds.jdbcUrl = "jdbc:mariadb://localhost:3306/DBNAME" //THIS WILL NOT WORK
val ds2 = HikariDataSource(config)
transaction(connect(ds2)) {
SchemaUtils.create( Tables... )
}
}
The reason I make a new datasource, is because otherwise I'll get this error:
java.lang.IllegalStateException: The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes. HikariConfigMXBean doesn't seem allow jdbcUrl changes.
There must be a more elegant way to do this, right?
It is not a good practice. Creating and filling db it is two separate processes. DB creates once by the DBA, then you just connect and use it. Your approach has huge security violation. User from the datasource must have create db privilege.
But if you want proceed with your current approach, first you should create a db without using datasource, then create datasource and connect to the db. Something like this
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.transactions.transaction
fun main(args: Array<String>) {
//LOAD proerties
val config = HikariConfig("/hikari.properties")
//Hikari properties content
// jdbcUrl=jdbc:mysql://localhost:3306/hikari
// driverClassName=com.mysql.cj.jdbc.Driver
// username=root
// password=<pwd here>
//Here replace dbname from jdbc url to empty
transaction(Database.connect(url = config.jdbcUrl.replace("hikari", ""),
driver = config.driverClassName,
user = config.username,
password = config.password)) {
SchemaUtils.createDatabase("hikari")
}
val ds = HikariDataSource(config)
transaction(Database.connect(ds)) {
SchemaUtils.create(Users)
}
}
object Users : Table() {
val id = varchar("id", 10) // Column<String>
val name = varchar("name", length = 50) // Column<String>
override val primaryKey = PrimaryKey(id, name = "PK_User_ID")
}

Import variables into aurelia-dialog view-model or view

Is there a way to import additional variables/data from the dialog-service to the controller?
For example I have an array of possible options in a form of my app-view. I fetch the data via an API from a server.
I'd like to edit an entry with an aurelia-dialog and don't want to fetch the data again to avoid unnecessary traffic in my app.
How can i pass the array additionally to the model. Pack it all together in an Object and unwrap it in the controller?
As far as I know the activate-method of the controller only takes one argument, doesn't it?
Thank you
Isn't the example in the repository exactly what you are looking for?
The person attribute is passed to the dialog service via the settings object (model: this.person). This may be data you fetched from the server. As you mentioned, you can of course add multiple objects to the model as well which will be available in the activate() method of your dialogs vm.
import {EditPerson} from './edit-person';
import {DialogService} from 'aurelia-dialog';
export class Welcome {
static inject = [DialogService];
constructor(dialogService) {
this.dialogService = dialogService;
}
person = { firstName: 'Wade', middleName: 'Owen', lastName: 'Watts' };
submit(){
this.dialogService.open({ viewModel: EditPerson, model: this.person}).then(response => {
if (!response.wasCancelled) {
console.log('good - ', response.output);
} else {
console.log('bad');
}
console.log(response.output);
});
}
}

How to skip value in config if it doesn't exist?

I am writing App, that need to read config at start. Some is not necessary for work.
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.getKey("key1");
}
//...
}
The problem that I need to find way to skip (do not try to find and parse) it if not exists and config. Now App try to parse config and show me error.
I found only one way - to wrap all in try-catch block, and if value can't be found in config in cantch block set it's to null.
What is the best way to do it?
I am using dini for config.
upd: (added example)
import std.stdio;
import std.path;
import std.file;
import dini;
void main()
{
string confpath = buildPath(getcwd, "config.ini");
if (!exists(confpath)) throw new Exception("ERROR: config.ini do not exists");
auto config = Ini.Parse(confpath);
try
{
string optionalkey;
if(config.getKey("optionalkey"))
{
optionalkey = config.getKey("optionalkey");
}
writeln(optionalkey); // nothing will shown, becouse exception
}
catch( Exception e)
{
writeln("Exception! :(");
writeln(e.msg);
}
}
Catching exception is one way, but it is not perfect (mainly if there will be many cases of optional configs). So better way is test if key exist:
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.hasKey("key1") ? config.getKey("key1") : "defaultValue";
}
//...
}
But ideal would be if dini has overload of getKey method so you can use something like this:
this.optionalkey = config.getKey("key1", "defaultValue");
But from sources I see it does not have it, but I plan to add it and make a PR.
UPDATE
PR: https://github.com/robik/DIni/pull/3
Wrote a pretty advanced ini file wrapper today which supports sections, comments, thread-safety, default values for reading, writing/reading using template values, entry checks etc.
You can get it here:
https://github.com/BaussProjects/baussini
Here is an example usage (example.d from the repo)
module main;
import baussini;
import std.stdio : writefln, readln;
void main() {
string fileName = "test.ini";
// Thread-safe instance, for a non thread-safe instance replace "true" with "false"
auto ini = new IniFile!(true)(fileName);
// Use open() for reading and close() for write. Both can be combined ...
if (!ini.exists()) {
ini.addSection("Root");
// Write way 1
ini.write!string("Root", "StringValue1", "Hello World!");
// Write way 2
ini.getSection("Root").write!int("IntValue1", 9001);
// Write way 3
ini.getSection("Root")
.write!string("StringValue2", "Hello Universe!")
.write!int("IntValue2", 1000000);
ini.close();
}
else {
ini.open();
// Read way 1
string stringValue1 = ini.read!string("Root", "StringValue1");
// Read way 2
int intValue1 = ini.getSection("Root").read!int("IntValue1");
// Read way 3
string stringValue2;
int intValue2;
ini.getSection("Root")
.read!string("StringValue2", stringValue2)
.read!int("IntValue2", intValue2);
writefln("%s is %s", "stringValue1", stringValue1);
writefln("%s is %s", "intValue1", intValue1);
writefln("%s is %s", "stringValue2", stringValue2);
writefln("%s is %s", "intValue2", intValue2);
readln();
}
}
In your case you could either use IniFile.hasKey or IniSection().hasKey()
Example:
// Check way 1
if (ini.hasKey("Root", "StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
// Check way 2
auto section = ini.getSection("Root");
if (section.hasKey("StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
You could also use default values.
string stringValue1 = ini.getSection("Root").read!string("StringValue1", "Default");
// stringValue1 will be "Default" if it doesn't exist within "Root"
The default value has to be a string input, but it will always convert the value of it to T.
Ex.
int defaultValue = ini.getSection("Root").read!int("IntValue3", "1000");
// defaultValue will be 1000 if it doesn't exist within "Root"
You can test if a key is present with hasKey
class ParseConfig
{
string optionalkey;
//...
this()
{
if (config.hasKey("key1"))
this.optionalkey = config.getKey("key1");
}
//...
}
assuming that we talk about the same dini

Configure UniCastBus in NServiceBus using IWantToRunBeforeConfigurationIsFinalized

I would like to "hook in" and tweak configuration to UnicastBus and was looking at doing this using IWantToRunBeforeConfigurationIsFinalized.
I would like to tweak/set the value for: ForwardReceivedMessagesTo. Any ideas on how that should be done?
Unfortunately due to a bug (see https://github.com/Particular/NServiceBus/issues/1960), the only possible way is to programmatically replace the whole UnicastBusConfig, eg:
class Foo : IProvideConfiguration<UnicastBusConfig>
{
public UnicastBusConfig GetConfiguration()
{
var unicastBusConfig = new UnicastBusConfig
{
ForwardReceivedMessagesTo = "FooBar",
};
unicastBusConfig.MessageEndpointMappings = new MessageEndpointMappingCollection();
unicastBusConfig.MessageEndpointMappings.Add(...);
return unicastBusConfig;
}
}
But that is quite ugly :(

Seems Like Groovy acts Differently on these two scenarios?

I have two domain classes like this, first namely Manager :
package com.mnm
class Manager {
String name;
static hasMany = [ project : Project, tasks : Tasks ]
static constraints = {
}
}
And second one namely, Project:
package com.mnm
class Project {
String projectTitle
String projectDescription
String description
static belongsTo = [ managers: Manager ]
static hasMany = [ tasks : Tasks ]
static constraints = {
}
}
And I wrote Integration test like this (to find the name of the projects via using Manager) :
void testCountProject() {
def manager = new Manager(name:'Anto').save()
manager.addToProject(new Project(projectTitle:'Grails'))
manager.addToProject(new Project(projectTitle:'Griffon'))
def noOfProjects = Manager.get(manager.id)
def found = noOfProjects.project.collect { it.projectTitle }
assertEquals(['Grails','Griffon'], found.sort())
}
Well there is no error in it and the test passes! But when I add more stuffs into to the same test like (now I'm trying the reverse, finding the Manager name via using Project) :
void testCountProject() {
def manager = new Manager(name:'Anto').save()
def project1 = new Project(projectTitle:'Grails').save()
manager.addToProject(project1)
manager.addToProject(new Project(projectTitle:'Griffon'))
def noOfProjects = Manager.get(manager.id)
def found = noOfProjects.project.collect { it.projectTitle }
assertEquals(['Grails','Griffon'], found.sort())
def noOfManager = Project.get(project.id)
def foundManager = noOfManager.managers.collect { it.name }
assertEquals(['Anto'],foundManager)
}
Now I get the error like this :
No signature of method: com.mnm.Manager.addToProject() is applicable for argument types: (null) values: [null] Possible solutions: addToProject(java.lang.Object), getProject()
Where I went wrong?
Thanks in advance.
You have the same problem in both cases, but the first isn't a proper test so it seems to work. The issue is that all properties are not-null by default, so your Project instances fail validation when you only set projectTitle.
In the first test you don't re-load the manager instance, you're still using the one in-memory because get() uses the Hibernate session as a 1st-level cache. If you flush and clear the session to force it to go to the database it will fail:
class MyTest extends GroovyTestCase {
def sessionFactory
void testCountProject() {
def manager = new Manager(name:'Anto')
manager.addToProject(new Project(projectTitle:'Grails'))
manager.addToProject(new Project(projectTitle:'Griffon'))
manager.save(flush: true)
sessionFactory.currentSession.clear()
def noOfProjects = Manager.get(manager.id)
def found = noOfProjects.project.collect { it.projectTitle }
assertEquals(['Grails','Griffon'], found.sort())
}
}
The second one fails because you call save() on the Project instance and it returns null when validation fails. You don't need to save Project instances because they will be transitively saved when the containing Manager gets saved - the more standard pattern is the one you use in the first test.
You have a few options. One is to fix the validation errors :) Another is to check for validation errors. This requires a separate save() call so you have access to the not-null instance:
def project1 = new Project(projectTitle:'Grails')
project1.save()
if (project1.hasErrors()) {
// handle errors
}
else {
manager.addToProject(project1)
}
The third is failOnError which will throw an exception when validation fails:
def project1 = new Project(projectTitle:'Grails').save(failOnError: true)
manager.addToProject(project1)