Is there a way to validate the "spring.jpa.hibernate.ddl-auto" property during application startup to ensure that it's set only to none? I want to force all deployments(including dev) to use liquibase.
Edit :- I also need to ensure that this property is not accidentally set in production, which could wipe out the data.
You can hook up on starting of your application by implementing ApplicationListener<ContextRefreshedEvent> class, like:
#Component
public class YourListner implements ApplicationListener<ContextRefreshedEvent> {
#Value("${spring.jpa.properties.hibernate.ddl-auto}")
private String hibernateDdlAuto;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!"none".equalsIgnoreCase(hibernateDdlAuto))
throw new MyValidationException();
}
}
Moreover, you can even make it more verbose by registering your own FailureAnalyzer.
As a best practice, you can maintain a universal application.properties/yml file and set the property (spring.jpa.hibernate.ddl-auto) there. Afterwards, maintain a separate property/yml file (application_*.properties/yml) which will fetch the properties from application.properties/yml file, by default.
Also, you can maintain other "common" properties in the parent file.
Related
I have a class which is disabled based on #Profile. I want to use it inside another class that is not conditional on the same profile:
#Component
#Profile("!local")
public class NotAlwaysExistingClass {
public void doThing() {
...
}
}
public class AlwaysExistingClass {
#Autowired(required=true)
NotAlwaysExistingClass notAlwaysExisting;
// Impossible for this to happen if profile is "local"
public void notAlwaysDoneThing() {
notAlwaysExisting.doThing();
}
...
}
I don't want to set the #Autowired(required=false) in all cases. Is it possible to disable the requirement only if a certain profile is active? I want to do this to make it more convenient to occasionally run the code locally, but without compromising the application or making major changes to the class structure.
I agree with #xerx593's #1 but you could also change that a little. You could extract an interface and make the class depending on it use it via an interface. Then you would have 2 beans that implement that interface and only available at a given time via #Profile selection. Remember #Autowired is by type by default.
Really this issue is similar (or the same) to having a couple of profiles for various needs of a datasource for example. In my projects, the local profile points to a local DB, the regular one points to some cloud db via env variables or whatever, and then I have a "cicd" profile for integration tests and those use a spun up H2 DB.
"Smart" (tricky) (?) approach:
NO-OP Bean/Profile ;)
Introduce an other "bean" (or "class"), which:
extends NotAlwaysExistingClass
takes #Profile("local") (so the logical complement of the "non-local" profile)
overrides doThing(), but with no-op/cheap/only logging code.
Done.
you don't need (further) refactorings
you can leave the required attribute (one of the profiles will always strike)
in "non-local" profile, you get the right bean
in "local" profile: nice logging/no-op :)
I have essentially the same question as here but am hoping to get a less vague, more informative answer.
I'm looking for a way to configure DropWizard programmatically, or at the very least, to be able to tweak configs at runtime. Specifically I have a use case where I'd like to configure metrics in the YAML file to be published with a frequency of, say, 2 minutes. This would be the "normal" default. However, under certain circumstances, I may want to speed that up to, say, every 10 seconds, and then throttle it back to the normal/default.
How can I do this, and not just for the metrics.frequency property, but for any config that might be present inside the YAML config file?
Dropwizard reads the YAML config file and configures all the components only once on startup. Neither the YAML file nor the Configuration object is used ever again. That means there is no direct way to configure on run-time.
It also doesn't provide special interfaces/delegates where you can manipulate the components. However, you can access the objects of the components (usually; if not you can always send a pull request) and configure them manually as you see fit. You may need to read the source code a bit but it's usually easy to navigate.
In the case of metrics.frequency you can see that MetricsFactory class creates ScheduledReporterManager objects per metric type using the frequency setting and doesn't look like you can change them on runtime. But you can probably work around it somehow or even better, modify the code and send a Pull Request to dropwizard community.
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you. Note that the below solution definitely works on config values you've provided, but it may not work for built in configuration values.
Also note that this doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.
I solved this with bytecode manipulation via Javassist
In my case, I wanted to change the "influx" reporter
and modifyInfluxDbReporterFactory should be ran BEFORE dropwizard starts
private static void modifyInfluxDbReporterFactory() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("com.izettle.metrics.dw.InfluxDbReporterFactory"); // do NOT use InfluxDbReporterFactory.class.getName() as this will force the class into the classloader
CtMethod m = cc.getDeclaredMethod("setTags");
m.insertAfter(
"if (tags.get(\"cloud\") != null) tags.put(\"cloud_host\", tags.get(\"cloud\") + \"_\" + host);tags.put(\"app\", \"sam\");");
cc.toClass();
}
I am using the PostContextCreate part of the life cycle in an e4 RCP application to create the back-end "business logic" part of my application. I then inject it into the context using an IEclipseContext. I now have a requirement to persist some business logic configuration options between executions of my application. I have some questions:
It looks like properties (e.g. accessible from MContext) would be really useful here, a straightforward Map<String,String> sounds ideal for my simple requirements, but how can I get them in PostContextCreate?
Will my properties persist if my application is being run with clearPersistedState set to true? (I'm guessing not).
If I turn clearPersistedState off then will it try and persist the other stuff that I injected into the context?
Or am I going about this all wrong? Any suggestions would be welcome. I may just give up and read/write my own properties file.
I think the Map returned by MApplicationElement.getPersistedState() is intended to be used for persistent data. This will be cleared by -clearPersistedState.
The PostContextCreate method of the life cycle is run quite early in the startup and not everything is available at this point. So you might have to wait for the app startup complete event (UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) before accessing the persisted state data.
You can always use the traditional Platform.getStateLocation(bundle) to get a location in the workspace .metadata to store arbitrary data. This is not touched by clearPersistedState.
Update:
To subscribe to the app startup complete:
#PostContextCreate
public void postContextCreate(IEventBroker eventBroker)
{
eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new AppStartupCompleteEventHandler());
}
private static final class AppStartupCompleteEventHandler implements EventHandler
{
#Override
public void handleEvent(final Event event)
{
... your code here
}
}
I am attempting to use Unitils to assist me in Database testing. I would like to use the Unitils/DBMaintain functionality for disabling constraints. However there is a few problems with this. I do not wish to use DBMaintain to create my databases for me however I wish to use its constraint disabling functionality. I was able to achieve this through the use of a custom module listed below:
public class DisableConstraintModule implements Module {
private boolean disableConstraints = false;
public void afterInit() {
if (disableConstraints) {
DatabaseUnitils.disableConstraints();
}
}
public void init(Properties configuration) {
disableConstraints = PropertyUtils.getBoolean("Database.disableConstraints", false, configuration);
}
}
This partially solves what I want however I wish to be able to only disable constraints for tables I will be using in my test. My tests will be running against a database with multiple schemas and each schema has hundreds of different tables. DatabaseUnitils.disableConstraints() disables the constraints for every table in every schema which would be far too time consuming and is unnecessary.
Upon searching the dbmaintain code I found that the Db2Database class does indeed contain a function for disabling constraints on a specific schema and table name basis however this method is protected. I could access this be either extending the Db2Database class or using reflection.
Next I need to be able to determine which schemas and tables I am interested in. I could do this by observing the #DataSet annotation to determine which schemas and tables are important based on what is in the xml. In order to do this I need to override the TestListener so I can instruct it to disable the constraints using the xml before it attempts to insert the dataset. This was my attempt at this:
public class DisableConstraintModule extends DbUnitModule {
private boolean disableConstraints = false;
private TableBasedConstraintsDisabler disabler;
public void afterInit() {
}
public void init(Properties configuration) {
disableConstraints = PropertyUtils.getBoolean("Database.disableConstraints", false, configuration);
PropertyUtils.getInstance("org.unitils.dbmaintainer.structure.ConstraintsDisabler.implClassName", configuration);
}
public void disableConstraintsForDataSet(MultiSchemaDataSet dataSet) {
disabler.disableConstraints(dataSet);
}
protected class DbUnitCustomListener extends DbUnitModule.DbUnitListener {
#Override
public void beforeTestSetUp(Object testObject, Method testMethod) {
disableConstraintsForDataSet(getDataSet(testMethod, testObject));
insertDataSet(testMethod, testObject);
}
}
}
This is what I would like to do however I am unable to get the #DataSet annotation to trigger my DbUnitCustomListener and instead it calls the default DBUnitModule DbUnitListener. Is there anyway for me to override which listener gets called when using the #DataSet annotation or is there a better approach all together for disabling constraints on a specific schema and table level for a DB2 Database?
Thanks
You have to tell Unitils to use your subclass of DbUnitModule. You do this using the unitils.module.dbunit.className property in your unitils.properties file. It sounds like you've got this part figured out.
The second part is to override DbUnitModule's getTestListener() in order to return your custom listener.
See this post for an example.
I have to access some application through an mbean so that I can change its application properties. Now i think this can be done in two ways:
First, either I ask the developer of that application to register all the application properties in an arraylist which my mbean will access.
Secondly, if there is any other way, such that the developer will only need to register editable properties and still my mbean can access both readable/editable(r/w) application properties.
Now since I don't know where these application properties are stored in the JVM, is there a way to implement my second point so that the mbean will just need to access that object and it will get all application properties?
Seems like you have some contradicting requirements here.
You want to change minimal code in the application.
You want to be cause to expose all properties for read and/or write.
You may or may not be talking about System.getProperty(...). If not then I guess you are talking about just fields in various objects.
There are (at least) two ways of doing this. Without knowing how you are exporting the mbeans from the source code right now, I can't tailor my answer to your specific config. My answer will instead show how you might use my SimpleJMX package to expose your properties.
If you are talking about System.getProperty(...) then you could write a JMX mbean that could query any property and return the value:
#JmxOperation(description = "Query for property")
public String queryForProperty(String name) {
return System.getProperty(name);
}
If, instead, you need to export of fields from some list of objects then you are going to either have to add annotations to each fields you are exporting or you are going to have to write beans that export the fields through delegation. I see no easy way and I know of no package that will easily export a series of objects for you without some sort of information about what is to be exported and how.
Using SimpleJMX, you can export a field by annotating either the field or the get method:
#JmxAttributeField(description = "Number of hits in the cache")
private int hitCount;
...
// this can also be specified as #JmxAttributeMethod on the getter/setter methods
#JmxAttributeMethod(description = "Number of misses in the cache")
private int getMissCount() {
return missCount;
}
The #JmxAttributeField supports a isWritable = true to allow the value to be set by JMX. You can also annotation the setter with #JmxAttributeMethod to make it writable.
If you don't want to add annotations to each of your classes, then you are going to have to write some sort of JMX container class that exports the values through delegation:
public class JmxPublisher {
private Class1 object1;
private Class2 object2;
...
public JmxPublisher(Class1 object1, Class2 object2) {
this.object1 = object1;
this.object2 = object2;
...
}
#JmxAttributeMethod(description = "Number of hits in the cache")
public int getClass1HitCount() {
return object1.getHitCount();
}
#JmxAttributeMethod(description = "Shutdown the background thread")
public void setClass2Shutdown(boolean shutdown) {
return object2.setShutdown(shutdown);
}
...
}
I also think you should express yourself more clearly.
From what I understood - why not providing a way to query the remote application, and get information on all properties and if they are Read-only, Write-only or RW?
This way the list of properties will not be mentioned at the source code of the client application - maybe you should let the user of the client application see the list of properties, and let him edit the properties he can edit, and prevent him from editing the properties he can't.