Spring-kafka Integration : Changing ConsumerConfig property without restarting applications - spring-kafka

I am trying to change ConsumerConfig properties by making change in a property file, which will be watched by #scheduled method( this will look for change in any property value and re-initialize the consumer after updating container factory bean instance picked from application context).
For example: If new broker is added to cluster, I would simply update broker list in property file.

The KafkaConsumer and its ConsumerConfig comes from the DefaultKafkaConsumerFactory into the KafkaMessageListenerContainer.
The DefaultKafkaConsumerFactory is injected with the Map of configs for the consumer. I think this is exactly the place where you should consider to change properties from your #Scheduled method. After changing them you should stop() listener container(s) and start() again - a new KafkaConsumer will be created based on fresh configs.
However a consumerGroupId indeed should be changed via ContainerProperties.
For this purpose there is just enough to change it via MessageListenerContainer.getContainerProperties().setGroupId(String groupId).

Related

Are custom repository instances created per request?

I am trying to create an application with mikro-orm and apollo-server-express, I want to use the batch processing and the caching of the Facebook dataloader.
Normally, Facebook dataloader instances are creates per request. If mikro-orm also creates custom repository instances per request and if all calls to EntityManager.getRepository() in the same request gets the same instance, it may be the perfect place to create the dataloader instances.
Repositories are created as singletons, so only one instance exists per EntityManager instance. You should fork this EM to have one instance per request, either manually, or via RequestContext middleware:
https://b4nan.github.io/mikro-orm/identity-map/
This way, each request will have its own EntityManager, that will have its own cache of repository instances.
Keep in mind that if you use RequestContext, you should get the request specific EntityManager from it, and get the repository from there:
// beware that this will return null if the context is not yet started
const em = RequestContext.getEntityManager();
// gets request specific repository instance
const repo = em.getRepository(Book);

Access Config Parameter without Container

What is the recommended way of accessing the global config parameters? I know you should inject just what you need, but the whole point of global parameters (in most cases) is to set application defaults. And I WANT the defaults to be universal, even if I allow passing in overrides on a function by function basis.
THE PROBLEM
I have a ViewVersion entity with a ViewVersionRepository where I have common functions for interacting with that entity.
One of these functions requires that I know a certain parameter from the config.yml (e.g. cms.save.newVersionSeconds so I know when it's been more than 30 minutes since the last save and I should create a new version record). The entity repository is not container aware though, so I can't access the config with the normal method:
$myParam = $container->getParameter('my.custom.param');
Inject From Controller
If I call this function from a controller, no problem I can get the config in the controller and inject the parameter into the repo function.
$myParam = $container->getParameter('my.custom.param');
$viewVersionRepository->myFunction($myParam)
Global Service
Or I can configure the the repo as a service:
gutensite_cms.view_version_repository:
class: Gutensite\CmsBundle\Entity\View\ViewVersionRepository
factory_service: 'doctrine.orm.cms_entity_manager'
factory_method: 'getRepository'
calls:
- [setLimit, ['%cms.limit.list.admin%']]
- [setNewVersionSeconds, ['%cms.save.newVersionSeconds%']]
And then set the parameter with setter injection via the calls arguments in the services.yml. And then load the service:
$viewVersionRepository = $this->container->get('gutensite_cms.view_version_repository');
Complication
However... I have a situation where I'm loading this viewVersionRepository within a doctrine onFlush event listener. And there I don't have access to the container (natively), so I can't actually load the global service. I have access to the entity though so I was loading the repo via:
$repo = $em->getRepository('GutensiteCmsBundle:View\ViewVersion);
But when you load it that way, it's not loaded as a service so the setter injection doesn't happen...
ONE SOLUTION
So I could pass the container into the global onFlush event listener service, so that I can load the ViewVersionRepository as a service (and for that matter have the container to the load the parameters if I wanted).
gutensite_cms.listener.is_versionable:
class: Gutensite\CmsBundle\EventListener\IsVersionableListener
#only pass in the services we need
arguments: [ "#gutensite_cms.entity_helper" ]
calls:
- [setContainer, ["#service_container"]]
tags:
- { name: doctrine.event_listener, event: onFlush }
But I'm told over and over and over again* to **ONLY inject the parameters you need. And to avoid injecting the entire container. This onFlush event is really quite dynamic, loading the corresponding onFlush event in any entity's repository that has an onFlush method. So in one entity repository the custom function may need access to one parameter, but in another entity repository the may need access another. So I can't really pass in just one parameter.
And it seems to me that passing the entire container makes your application far more coupled than if you were to just used the vilified $GLOBALS or CONSTANT for your global default config. So surely there is a better way to avoid both these evils. Not to mention you should NEVER inject the container into an entity repository.
So isn't there some way to access the global config parameters WITHOUT injecting the entire blessed container? Does no one EVER need global config parameters in an entity repository? Sure I could move this function to another service... but why? This is one of the basic functions of this entity, e.g. it determines if it should be versioned or not.

Same stateless bean in two ears

I have the same EJB module with a bean inside an EAR that is server side and an EAR that is the client side.
Can I have this situation?
Because I'm getting this error http://justpaste.it/gfs3
without understand how to fix it.
You have answer in the stack trace:
The short-form default binding 'com.demo.view.RitornaPersonaRemote'
is ambiguous because multiple beans implement the interface :
[RitornaPersonaSenzaClientEAR#RitornaPersonaSenzaClient.jar#RitornaPersona,
RitornaPersonaWebSenzaClientEAR#RitornaPersonaSenzaClient.jar#RitornaPersona].
Provide an interface specific binding or use the long-form default binding on lookup.]
If you are asking whether you may have same EJB jar in multiple project - the answer is yes you can. However during deployment you have to use long-form JNDI, provide different JNDI name for beans in other module or disable short names. You cannot register two beans under same name.
Long name would be in the form RitornaPersonaSenzaClientEAR#RitornaPersonaSenzaClient.jar#com.demo.view.RitornaPersonaRemote
See detailed info here - EJB 3.0 and EJB 3.1 application bindings overview
UPDATE
To disable short names perform the following steps:
Go to Application servers > server1 > Process definition > Java Virtual Machine > Custom properties
Define new custom property com.ibm.websphere.ejbcontainer.disableShortDefaultBindings with value * to disable short bindings for all apps or AppName1|AppName2 to just disable short bindings in selected apps.
Example default bindings are shown in SystemOut.log:
The binding location is: ejblocal:JPADepEar/JPADepEJB.jar/TableTester#ejb.TableTester
The binding location is: ejblocal:ejb.TableTester
The binding location is: java:global/JPADepEar/JPADepEJB/TableTester!ejb.TableTester
And with disableShortDefaultBindings property set there is no short form:
The binding location is: ejblocal:JPADepEar/JPADepEJB.jar/TableTester#ejb.TableTester
The binding location is: java:global/JPADepEar/JPADepEJB/TableTester!ejb.TableTester
There is a bug in the documentation and the correct property is com.ibm.websphere.ejbcontainer.disableShortDefaultBindings not com.ibm.websphere.ejbcontainer.disableShortFormBinding
In my case:- i did install abc.ear and xyz.ear both ear was independent do dependency with each other.
I was calling abc.ear using client-lookup but that was giving me
com.ibm.websphere.naming.CannotInstantiateObjectException: Exception occurred while the JNDI NamingManager was processing a javax.naming.Reference object.
[Root exception is com.ibm.websphere.ejbcontainer.AmbiguousEJBReferenceException: The short-form default binding
'com.ejb.abc' is ambiguous because multiple beans implement the interface :
[xyz-ear#rabc-ejb-1.0.jar#abcInrerfaceImpl, rabc-ear#rabc-ejb-1.0.jar
abcInrerfaceImpl]. Provide an interface specific binding or use the long-form default binding on lookup.]
my Solution was:-
i removed the abc.jar that was inside another application(xyz.ear)
C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\wstemp\92668751\workspace\cells\mypc00Node01Cell\applications\xyz-ear.ear
'
Then solution client-lookup works fine.
To avoid this in future this is better practice to create separate node on your IBM-WAS server and install both application on different node.
So both application component will not mess up.

How can I get an Alfresco ContentService object?

I am attempting to read the content of a file in Alfresco. I have seen examples that use
ContentService. Unforunately, when I try to use the example code, the ContentService
is not available.
I have added ContentService as a managed property of my managed bean in faces-config.xml
<managed-property>
<property-name>contentService</property-name>
<value>#{ContentService}</value>
</managed-property>
In my java code, I am using
ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
final ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
// contentService is an instance variable.
this.contentService = serviceRegistry.getContentService();
I am getting this Exception:
javax.faces.el.EvaluationException: Exception while invoking expression #{DeployAssetQADialog.start}
caused by:
javax.faces.el.PropertyNotFoundException: Bean: com.XXXXXXXXXX.CCCCCCCC.DeployAssetDialog, property: contentService
Can anyone tell me if there is something that I am missing? Thanks
PropertyNotFoundException sounds like your managed bean is missing a setter method.
How to expose spring managed beans to jsf may depend on the spring and/or jsf version you are using. Have a look at Spring beans injected into JSF Managed Beans for an example.
Finally, Make sure your Alfresco spring context is initialized before jsf kicks in.
Many issues in code
1) For each services which are injected you need to add getter setter method for them.
If you add getter setter for contentservice you can get rid of your error.
2) Other thing is you are trying to get conentservice though service registry in that case you need to inject service registry and add getter setter for that. Otherwise get contentservice instance directly as it is injected though faces-config and provided you have added getter setter for it you can directly use that instance of contentservice.

Any way to programmatically set BizTalk Message Context property?

Is there any way to set BTS.RetryCount or WCF.Action not in a Message Assignment Shape?
I have a special orchestration for dynamic message sending, its parameters are Message and ServiceName and it has a dynamic port which is easily configured with UDDI service. The thing I can't do in that orchestrations is I can't set WCF.Action for a message, I should create a new one because it's prohibited in BizTalk to modify a message anywhere outside a Construct shape. So it's very inconvenient for me to set this property every time I want to send a message, I thought I would be able to do all the UDDI & routing stuff in a one dedicated orchestration which I later can just call with parameters.
Can you not modify those properties in a pipeline component? You can then execute the pipeline inside the orchestration.
UPDATE
What I mean is you can create a pipeline component to set the context properties of the message as it passes through. Then you can create a pipeline which includes this component and execute it inside your orchestration by passing a message through it. This message will then have those context properties set.
Could you not create a new message in an assignment shape, of the same type as the message you need to modify
NewMessage = OldMessageWithTheDynamicPropertiesSet;
and copy over all the properties
NewMessage(*)* = OldMessageWithTheDynamicPropertiesSet(*);
and then set the properties you need to set. You can also set the WCF action that way.
NewMessage(WCF.Action)=....
NewMessage(BTS.REtryCount)= 666
And then you send this new message out.

Resources