How do I set a global error handler without overriding existing RabbitListenerContainerFactory in Spring AMQP? - spring-amqp

I have a situation where there are many downstream projects using a same common library holding the RabbitMQ configuration.
I want to add a global error handler in such common configuration but pretty much all online documentation says that I have to declare my own RabbitListenerContainerFactory so that I can set my error handler in the bean definition code (e.g. via autowiring a SimpleRabbitListenerContainerFactoryConfigurer whose by the way I haven't fully understood the purpose).
However, I don't want to override any existing RabbitListenerContainerFactory, because some of the downstream projects declare their own implementation of it, and I don't want to go and set my global error handler for each of them. I want to declare the global error handler only in the common library and once for all.
How can I do that by using the existing implementation of RabbitListenerContainerFactory whatever that is?

Seems like I have found a working solution.
#Configuration
public class SimpleRabbitListenerContainerFactoryExtraConfig {
public SimpleRabbitListenerContainerFactoryExtraConfig(
final SimpleRabbitListenerContainerFactory factory,
final MyErrorHandler handler) {
factory.setErrorHandler(handler);
}
}

Related

How to enable Serilog minimum level overrides without particular convention of calling ForContext?

This article on Serilog minimum level overrides states:
The first argument of Override is a source context prefix, which is normally matched against the namespace-qualified type name of the class associated with the logger.
For this so-called "normal" behavior, wouldn't I need to manually set the .ForContext<>() differently for each class my logger is called from? In other words, how are namespace-specific minimum log levels supposed to work without a specific convention of how .ForContext is set?
If that makes sense, then how can I set ForContext automatically without calling it with a different argument everywhere?
For this so-called "normal" behavior, wouldn't I need to manually set
the .ForContext<>() differently for each class my logger is called
from?
Yes, you would. A common way of doing it is by using the Log.ForContext<T>() on each class, in a member variable that gets shared across the different methods of your class (so that all logs get written with the same context). e.g.
public class SomeService
{
private readonly ILogger _log = Log.ForContext<SomeService>();
// ...
}
public class SomeRepository
{
private readonly ILogger _log = Log.ForContext<SomeRepository>();
// ...
}
If you are using an IoC container such as Autofac, you can have the .ForContext<>() call happen automatically when classes are resolved by the IoC container (by using constructor injection, for example).
If you are using Autofac specifically, you could use AutofacSerilogIntegration that takes care of that. There might be similar implementations for other IoC containers (or you'd have to implement your own).
If you are using Microsoft's Generic Host, then you'll need to configure it to use a custom ServiceProviderFactory which will be responsible for creating the instances and making the call to .ForContext<>()... An easy route is to integrate Autofac with Microsoft's Generic Host and then leverage the AutofacSerilogIntegration I mentioned above.

What is the use of requireBinding?

I am relatively new to Guice and trying to understand the usage of requireBinding and when/why to use it.
As per my understanding, while creating an injector Guice goes through the code of configure() method of all the modules and builds a dependency graph.
If Guice builds the dependency graph in itself then why does a module need to add a requireBinding? As long as I could understand the usage of requireBinding is to add an explicit dependency on a class which guice's dependency graph seems to be doing anyway.
I would like to understand that when should we use requireBinding and what is the impact of not using it in a module.
I have read Guice's official documentation and search on all the existing questions on Stackoverflow/any other blog but couldn't find a satisfying answer to the above question.
Adding to the original question.
Looking at the Source code of the AbstractModule the implementation looks like
protected void requireBinding(Key<?> key) {
this.binder().getProvider(key);
}
protected void requireBinding(Class<?> type) {
this.binder().getProvider(type);
}
Which you would assume will not have any side effect as it's a "get" call.
But on the other hand looking it the binder itself it adds some element to a list of elements of type ProviderLookup
public <T> Provider<T> getProvider(Dependency<T> dependency) {
ProviderLookup<T> element = new ProviderLookup(this.getElementSource(), dependency);
this.elements.add(element);
return element.getProvider();
}
I've always though of requireBinding() as a contract for the Module.
You are correct that the graph would eventually fail when you call #get() or tried to inject an object that depends on the binding. However, I believe requireBinding will cause a failure when the Injector is created vs when the object is created (via the injector). When I was at Google, it functioned more as a contract, less as something with consequential behavior.

How to inject an e4view with Guice injection

I am working on an existing Eclipse RCP based on Luna which consists of 99% 3.x API. We want to change this in an ongoing process; so when I was given the task of creating a new view, I wanted to use the new (in Luna, anyways) e4view element for the org.eclipse.ui.views extension point.
My problem is that part of the RCP uses xtext and thus, several components are available by using Guice.
I am now stranded with something like this
public class MyViewPart
{
#Inject // <- should be injected via Guice (I used #com.google.inject.Inject, otherwise E4DI would complain)
ISomeCustomComponent component;
#PostConstruct // <- should be called and injected via E4 DI
public void createView(Composite parent)
{
// ...
}
}
To get this injected with Guice, I would usually use an AbstractGuiceAwareExecutableExtensionFactory (as usually done in Xtext contexts) like this:
<plugin>
<extension
point="org.eclipse.ui.views">
<e4view
class="my.app.MyExecutableExtensionFactory:my.app.MyViewPart"
id="my.app.view"
name="my view"
restorable="true">
</e4view>
</extension>
</plugin>
But I did not expect this to work, because I thought it would bypass the E4 mechanism (actually, it seems to be the other way round and the e4view.class element seems to ignore the extension factory and just uses my.app.MyViewPart to inject it with E4DI. To be sure, I have set a class loading breakpoint to MyViewPart which is hit from ContextInjectionFactory.make()).
As I said, I didn't expect both DI frameworks to coexist without conflict, so I think the solution to my problem would be to put those object which I need injected into the E4 context.
I have googled a bit but I have found multiple approaches, and I don't know which one is the "correct" or "nice" one.
Among the approaches I have found, there are:
providing context functions which delegate to the guice injector
retrieving the objects from guice and configure them as injector bindings
retrieving the objects from guice, obtain a context and put them in the context
(The first two approaches are mentioned in the "Configure Bindings" section of https://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection)
And of course I could get the objects from Guice in the MyViewPart implementation, but that's not what I want...
[Edit:] In the meantime I have explored the options above a bit more:
Context Functions
I tried to register the context functions as services in the Bundle Activator with this utility method:
private void registerGuiceDelegatingInjection(final BundleContext context, final Class<?> clazz)
{
IContextFunction func = new ContextFunction()
{
#Override
public Object compute(final IEclipseContext context, final String contextKey)
{
return guiceInjector.getInstance(clazz);
}
};
ServiceRegistration<IContextFunction> registration =
context.registerService(IContextFunction.class, func,
new Hashtable<>(Collections.singletonMap(
IContextFunction.SERVICE_CONTEXT_KEY, clazz.getName()
)));
}
and called registerGuiceDelegatingInjection() in the BundleActivator's start() method for each class I needed to be retrieved via Guice.
For some reason, however, this did not work. The service itself was registered as expected (I checked via the OSGi console) but the context function was never called. Instead I got injection errors that the objects could not be found during injection. Maybe the context functions cannot be contributed dynamically but have to be contributed via declarative services, so they are known as soon as the platform starts?
(Answer here is: yes. As the JavaDoc to IContextFunction says: Context functions can optionally be registered as OSGi services [...] to seed context instances with initial values. - and since the application context already exists when my bundle is started, the dynamically registered service is not seen by the ContextFactory in time).
Injector Bindings
I quickly found out that this solution does not work for me, because you can only specify an interface-class to implementation-class mapping in the form
InjectorFactory.getDefault().addBinding(IMyComponent.class).implementedBy(MyComponent.class)
You obviously cannot configure instances or factories this way, so this is not an option, because I need to delegate to Guice and get Guice-injected instances of the target classes...
Putting the objects in the context
This currently works for me, but is not very nice. See answer below.
[Edit 2:] As I have reported, putting the objects in the (application) context works for me. The downside is that having the objects in the application context is too global. If I had two or more bundles which would require injection of object instances for another DSL, I would have to take care (e.g., by using #Named annotations) to not get the wrong instance injected.
What I would like better is a way to extend the Part's context with which my e4view is created and injected directly. But so far I have not found a way to explicitly target that context when putting in my instances ...
Thanks for any further hints...
Try the processor mechanism of E4: You should be using a (Pre or Post) Processor (along with the PostContextCreate annotation) to register your POJOs into the (global) IEclipseContext.
The solution that worked for me best so far was getting the IEclipseContext and put the required classes there myself during the bundle activator's start() method.
private void registerGuiceDelegatingInjection(final BundleContext context, final Class<?> clazz)
{
IServiceLocator s = PlatformUI.getWorkbench();
IEclipseContext ctx = (IEclipseContext) s.getService(IEclipseContext.class);
ctx.set(clazz.getName(), guiceInjector.getInstance(clazz));
}
This works at least for now. I am not sure how it works out in the future if more bundles would directly put instances in the context; maybe in the long-term named instances would be needed. Also, for me this works, because the injected objects are singletons, so it does not do any harm to put single instances in the context.
I would have liked the context function approach better, but I could not get it to work so far.

CDI and multiple instances

I'm just investigating possibilities of DI frameworks and I made some stupid example for it. I have simple service.
public class Service implements ServiceI {
private Source source;
private Translator translator;
#Inject
public Service(Translator translator, Source source) {
this.translator = translator;
this.source = source;
}
I want to have two instances of this service one which is initiated with TranslatorA and SourceA and second which will be injected with different values.
How can one have two instances with different beans injected inside?
I'm interested in ways how to achieve this in both Guice and Weld CDI.
So far I created multiple Guice modules and specify bind-to in it as I like. But I'm not completely sure if it is correct way. And this completely fails in CDI as there are no modules.
I thing that having multiple instances must be pretty common case or am I wrong?
The way you would do this with CDI is by setting up a producers for translator and source. It's the only way to control which implementations are used for injection at runtime. The implementation details may vary based on your exact needs but something like this should get you on the right track
#Produces
public Translator produceTranslator(#Dependent TranslatorA implA, #Dependent TranslatorB implB) {
return checkRuntimeCondition() ? implA : implB;
}
And the same for the source. That way when you inject Service, CDI'll call the producer method for each parameter and use a runtime condition to select the implementation. YMMV on the details, you may need to set up additional qualifiers to avoid ambiguity.

How to avoid having injector.createInstance() all over the place when using guice?

There's something I just don't get about guice: According to what I've read so far, I'm supposed to use the Injector only in my bootstrapping class (in a standalone application this would typically be in the main() method), like in the example below (taken from the guice documentation):
public static void main(String[] args) {
/*
* Guice.createInjector() takes your Modules, and returns a new Injector
* instance. Most applications will call this method exactly once, in their
* main() method.
*/
Injector injector = Guice.createInjector(new BillingModule());
/*
* Now that we've got the injector, we can build objects.
*/
RealBillingService billingService = injector.getInstance(RealBillingService.class);
...
}
But what if not all Objects I ever need can be created during startup? Maybe I want to respond to some user interaction when the application is running? Don't I have to keep my injector around somewhere (e.g. as a static variable) and then call injector.getInstance(SomeInterface.class) when I need to create a new object?
Of course spreading calls to Injector.getInstance() all over the place seems not to be desirable.
What am I getting wrong here?
Yes, you basically only should use the Injector to create get the instance for the root-object. The rest of the application shouldn't touch the Guice-Container. As you've noticed, you still need to create some objects when required. There are different approaches for doing that, each suitable for different needs.
Inject a Provider
Provider is a interface from Guice. It allows you to request a new instance of a object. That object will be created using Guice. For example.
class MyService{
private Provider<Transaction> transactionProvider;
public MainGui(Provider<Transaction> transactionProvider){
this.transactionProvider = transactionProvider;
}
public void actionStarted(){
Transaction transaction = transactionProvider.get();
}
Build a Factory
Often you need some kind of factory. This factory uses some injected services and some parameters and creates a new object for you. Then you use this factory for new instances. Then you inject that factory and use it. There also help for this with the AssistedInject-extension
I think with these two possibilities you rarely need to use the Guice-Injector itself. However sometimes is still appropriate to use the injector itself. Then you can inject the Injector to a component.
To extend on the answer Gamlor posted, you need to also differentiate between the object types you are using.
For services, injection is the correct solution, however, don't try to always make data objects (which are generally the leafs in your object graph) injectable. There may be situations where that is the correct solution, but injecting a Provider<List> is probably not a good idea. A colleague of mine ended up do that, it made the code base very confusing after a while. We just finished cleaning it all out and the Guice modules are much more specific now.
In the abstract, I think the general idea is that if responding to user events is part of the capabilities of your application, then, well...
BillingService billingService = injector.getInstance(BillingService.class);
billingService.respondToUserEvent( event );
I guess that might be a little abstract, but the basic idea is that you get from Guice your top-level application class. Judging from your question, I guess that maybe BillingService isn't your top-level class?

Resources