DI with configuration - java

I newbie in java i don't know of all possibilites. I want to know can i implement something like this:
class DIConfig {
// create at start of application (integration with javaee container)
// load configurable files and stores all configuration
}
class Foo {
// use DIConfig to inject value stored in DIConfig to String url
#Config("general.url")
String url;
public void bar() {
// same thing with local variable
#Config("export.maxRows")
int maxRows;
}
}
It's available? How can i do it?
My trouble - i don't understand how to using annotation execute some code and stores result in annotaed variable.
Seems it not possible.
All DI frameworks use something like binder - i've many classes that using configuration property and create all of this classes via binder or something like this - impossible. I search mechanism that don't use any binders. Somethinh like interceptors (AOP) but initialize variable instead wrap method invoke.

Related

Modifying annotation value in superclass and dynamically instantiating child classes with new value

We are using Spring Cloud Stream as the underlying implementation for event messaging in our microservice-based architecture. We wanted to go a step further and provide an abstraction layer between our services and the Spring Cloud Stream library to allow for dynamic channel subscriptions without too much boilerplate configuration code in the services themselves.
The original idea was as follows:
The messaging-library provides a BaseHandler abstract class which all individual services must implement. All handlers of a specific service would like to the same input channel, though only the one corresponding to the type of the event to handle would be called. This looks as follows:
public abstract class BaseEventHandler<T extends Event> {
#StreamListener
public abstract void handle(T event);
}
Each service offers its own events package, which contains N EventHandlers. There are plain POJOs which must be instantiated programmatically. This would look as follows:
public class ServiceEventHandler extends BaseEventHandler<ImportantServiceEvent> {
#Override
public void handle(ImportantServiceEvent event) {
// todo stuff
}
}
Note that these are simple classes and not Spring beans at this point, with ImportantServiceEvent implementing Event.
Our messaging-library is scanned on start-up as early as possible, and performs handler initialization. To do this, the following steps are done:
We scan all available packages in the classpath which provide some sort of event handling and retrieve all subclasses of BaseEventHandler.
We retrieve the #StreamListener annotation in the hierarchy of the subclass, and change its value to the corresponding input channel for this service.
Since our handlers might need to speak to some other application components (repositories etc.), we use DefaultListableBeanFactory to instantiate our handlers as singleton, as follows:
val bean = beanFactory.createBean(eventHandlerClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
beanFactory.registerSingleton(eventHandlerClass.getSimpleName(), bean);
After this, we ran into several issues.
The Spring Cloud Stream #StreamListener annotation cannot be inherited as it is a method annotation. Despite this, some mechanism seems to be able to find it on the parent (as the StreamListenerAnnotationBeanPostProcessor is registered) and attempts to perform post-processing upon the ServiceEventHandler being initialized. Our assumption is that the Spring Cloud Stream uses something like AnnotationElementUtils.findAllMergedAnnotations().
As a result of this, we thought that we might be able to alter the annotation value of the base class prior to each instantiation of a child class. Due to this, we thought that although our BaseEventHandler would simply get a new value which would then stay constant at the end of this initialization phase, the child classes would be instantiated with the correct channel name at the time of instantiation, since we do not expect to rebind. However, this is not the case and the value of the #StreamListener annotation that is used is always the one on the base.
The question is then: is what we want possible with Spring Cloud Stream? Or is it rather a plain Java problem that we have here (does not seem to be the case)? Did the Spring Cloud Stream team foresee a use case like this, and are we simply doing it completely wrong?
This question was also posted on on the Spring Cloud Stream tracker in case it might help garner a bit more attention.
Since the same people monitor SO and GitHub issues, it's rather pointless to post in both places. Stack Overflow is preferred for questions.
You should be able to subclass the BPP; it specifically has this extension point:
/**
* Extension point, allowing subclasses to customize the {#link StreamListener}
* annotation detected by the postprocessor.
*
* #param originalAnnotation the original annotation
* #param annotatedMethod the method on which the annotation has been found
* #return the postprocessed {#link StreamListener} annotation
*/
protected StreamListener postProcessAnnotation(StreamListener originalAnnotation, Method annotatedMethod) {
return originalAnnotation;
}
Then override the bean definition with yours
#Bean(name = STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME)
public static StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor() {
return new StreamListenerAnnotationBeanPostProcessor();
}

Direct communication between aspectJ aspects?

i have a few different aspects in my application and i want them to be able to communicate. is it possible to somehow access one from another or the only way is to have some static field serving as a 'message board'?
i'm talking about aspectj, NOT spring aop. also i'm using the .aj files so i'm not limited by the annotation-only syntax
Edit:
To provide sample use case and the code i'm thinking about: Let's say i want to have different aspects guarding my banking app against frauds. And i want them to communicate sometimes to decide together how to react on new types of timeseries and together change the fraud detection policy:
public aspect MyAspect1 {
private MyState myState = ...
pointcut myPointcut(): ...
before(): myPointcut {
MyAspect2 other = ... // how to get the reference to another similar aspect?
}
}

Configuring DropWizard Programmatically

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();
}

Is there a data binder using aspects and annotations?

I want to write a java application using swing, spring and hibernate.
I want to use a data binder to populate the gui with the values of a bean, and I also want it to reflect updates of the bean in the gui.
It seems there is a way to do that in spring, using the DataBinder, but as far as I understand you need to implement the property-change code in the beans yourself, and you need to connect the properties of the bean to the setter methods of the gui using strings which I dislike.
I came across this to prevent the manual implementation of the property-change support in the beans:
https://github.com/damnhandy/Handy-Aspects
Now I'm looking for a data binding framework that I can use together with this, which also supports annotations to minimize and ease the configuration of the binder.
I would hope that I can annotate the setters of the gui with an annotation which takes the name of the property - or, even better, if it has the same name like the property, it wires up automatically.
For example, if I have a Person class with properties name and age, I would like to configure the gui like that:
#GUI
public class PersonGui{
[...]
#BoundField
public void setName(String name){
...
}
#BoundField(property="age")
public void setTheAge(int theAge){
...
}
}
Is there anything like this?
I wrote a library that uses spring data binding for Swing using the "same name convention".
Sample code is in https://github.com/chelu/jdal-samples/tree/master/library
Maybe you are interested on trying it.

Registering and updating application properties using JMX

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.

Categories

Resources