Change payload within Spring integration Filter - spring-integration

I am writing a filter with Spring Integration.
In this filter I check a set of preconditions. If any precondition is not satisfied, I would need to change message payload (or even header) to add the set of actions to be done by the user to satisfied it and return it to the user over the discart channel.
I could use a service activator but I think the filter would more descriptive in this case.
What is the cleanest way to make it?
This is a sort of pseudocode:
#Filter
public boolean checkEventPreconditions(Message<?> messageIn)
{
//Here I am returning the set of actions to satisfied preconditions
List<Integer> actionsId = returnActions();
if(actionsId.isEmpty())
{
return true;
}
else
{
//Here I need to add actionsId to the message
return false;
}
}
Thanks!

No, don't mix concerns: filter just has to check if send message further or discard it.
To change the message is a responsibility of transformer.
So, what you want to do should be placed within discard flow.

Related

spring integration dsl configure idempotent receiver to identify duplicates

I am using DUPS_OK_ACKNOWLEDGE mode while consuming messages from queue, i need to detect duplicates and ignore them.
.from(Jms.messageDrivenChannelAdapter(activeMQConnectionFactory)
.destination(sourceQueue)
.configureListenerContainer(spec -> {
spec.sessionTransacted(false);
spec.sessionAcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);
}))
.transform(orderTransformer)
.handle(orderService, "save")
.get();
I have an idempotent receiver advice.
#Bean
public IdempotentReceiverInterceptor idempotentReceiverInterceptor() {
IdempotentReceiverInterceptor idempotentReceiverInterceptor = new IdempotentReceiverInterceptor(new MetadataStoreSelector(m ->
(String) m.getHeaders().get("JMSMessageId")));
idempotentReceiverInterceptor.setDiscardChannelName("ignoreDuplicates");
idempotentReceiverInterceptor.setThrowExceptionOnRejection(false);
return idempotentReceiverInterceptor;
}
I am stuck with 2 things
How to i configure/call this advice in the
Jms.messageDrivenChannelAdapter?
If i need the metadata store to be in oracle/mysql, how does the table look like any example links
The Idempotent Receiver is definitely a matter of consumer, but not producer, which is Jms.messageDrivenChannelAdapter(). In terms of Spring Integration, of course.
If you don't want to pass duplicates to downstream, you need to configure such an Advice on the consumer after that Jms.messageDrivenChannelAdapter(). In your case it is .transform(orderTransformer). So, the code might look like this:
.transform(orderTransformer, e -> e.advice(idempotentReceiverInterceptor()))
The oracle/mysql MetadataStore is here - JdbcMetadataStore since 5.0: https://docs.spring.io/spring-integration/docs/5.0.5.RELEASE/reference/html/jdbc.html#jdbc-metadata-store

Spring Aggregation Group

I did create an aggregate service as below
#EnableBinding(Processor.class)
class Configuration {
#Autowired
Processor processor;
#ServiceActivator(inputChannel = Processor.INPUT)
#Bean
public MessageHandler aggregator() {
AggregatingMessageHandler aggregatingMessageHandler =
new AggregatingMessageHandler(new DefaultAggregatingMessageGroupProcessor(),
new SimpleMessageStore(10));
//AggregatorFactoryBean aggregatorFactoryBean = new AggregatorFactoryBean();
//aggregatorFactoryBean.setMessageStore();
aggregatingMessageHandler.setOutputChannel(processor.output());
//aggregatorFactoryBean.setDiscardChannel(processor.output());
aggregatingMessageHandler.setSendPartialResultOnExpiry(true);
aggregatingMessageHandler.setSendTimeout(1000L);
aggregatingMessageHandler.setCorrelationStrategy(new ExpressionEvaluatingCorrelationStrategy("requestType"));
aggregatingMessageHandler.setReleaseStrategy(new MessageCountReleaseStrategy(3)); //ExpressionEvaluatingReleaseStrategy("size() == 5")
aggregatingMessageHandler.setExpireGroupsUponCompletion(true);
aggregatingMessageHandler.setGroupTimeoutExpression(new ValueExpression<>(3000L)); //size() ge 2 ? 5000 : -1
aggregatingMessageHandler.setExpireGroupsUponTimeout(true);
return aggregatingMessageHandler;
}
}
Now i want to release the group as soon as a new group is created, so i only have one group at a time.
To be more specific i do receive two types of requests 'PUT' and 'DEL' . i want to keep aggregating per the above rules but as soon as i receive a request type other than what i am aggregating i want to release the current group and start aggregating the new Type.
The reason i want to do this is because these requests are sent to another party that don't support having PUT and DEL requests at the same time and i can't delay any DEL request as sequence between PUT and DEL is important.
I understand that i need to create a custom release Pojo but will i be able to check the current groups ?
For Example
If i receive 6 messages like below
PUT PUT PUT DEL DEL PUT
they should be aggregated as below
3PUT
2 DEL
1 PUT
OK. Thank you for sharing more info.
Yes, you custom ReleaseStrategy can check that message type and return true to lead to the group completion function.
As long as you have only static correlationKey, so only one group is there in the store. When your message is stepping to the ReleaseStrategy, there won't be much magic just to check the current group for completion signal. Since there are no any other groups in the store, there is no need any complex release logic.
You should add expireGroupsUponCompletion = true to let the group to be removed after completion and the next message will form a new group for the same correlationKey.
UPDATE
Thank you for further info!
So, yes, your original PoC is good. And even static correlationKey is fine, since you are just going to collect incoming messages to batches.
Your custom ReleaseStrategy should analyze MessageGroup for a message with different key and return true in that case.
The custom MessageGroupProcessor should filter a message with different key from the output List and send that message to the aggregator back to let to form a new group for a sequence for its key.
i ended up implementing the below ReleaseStrategy as i found it simpler than removing message and queuing it again.
class MessageCountAndOnlyOneGroupReleaseStrategy implements org.springframework.integration.aggregator.ReleaseStrategy {
private final int threshold;
private final MessageGroupProcessor messageGroupProcessor;
public MessageCountAndOnlyOneGroupReleaseStrategy(int threshold,MessageGroupProcessor messageGroupProcessor) {
super();
this.threshold = threshold;
this.messageGroupProcessor = messageGroupProcessor;
}
private MessageGroup currentGroup;
#Override
public boolean canRelease(MessageGroup group) {
if(currentGroup == null)
currentGroup = group;
if(!group.getGroupId().equals(currentGroup.getGroupId())) {
messageGroupProcessor.processMessageGroup(currentGroup);
currentGroup = group;
return false;
}
return group.size() >= this.threshold;
}
}
Note that i did used new HeaderAttributeCorrelationStrategy("request_type") instead of just FOO for CollorationStrategy

Grails domain objects - limit access to specific user

Is there a way to limit access to Grails domain objects across the board to the owner of the object?
For example, I can make an assert easily, but I don't want to duplicate that everywhere, or risk missing a spot.
This isn't exactly the same as multi-tenancy because it's not just a tenant ID - it may be specific business logic for different domain objects.
class MyDomain {
String name
String user
}
class MyController {
def show(Long id) {
def obj = MyDomain.get(id)
// *** How do I not do copy-paste this line in each individual controller
// that touches MyDomain?? ***
assert obj.user == CURRENT_USER
return obj
}
}
There are so many ways to handle such scenarios, as other answers are suggesting, however, I think one proper way to approach it is to use Spring Security Plugin and spring-security-acl plugin. ACL plugin will drill down into object level and helps you to control
According to doc
"The ACL plugin adds Domain Object Security support to a Grails
application that uses Spring Security."
The combination of both security core and ACL can help you accomplish what you need.
Filter might be one way, another way is to adjust your queries if possible. You would probably need to be able to search for some other criteria other than the ID. Without understanding your use case a little more, it is hard to give a better answer.
def show(String someValue) {
def currentUser = howeverYouGetYourUser
def obj = MyDomain.findByUserAndSomeValue(currentUser, someValue)
if (obj) {
// yeah!!!
} else {
// boo!!
}
}
Ideally, if you are looking for specific data for a specific user, ID isn't really the way to go.
Iam not sure if you can do it in domain level but one way is using filters. There is a filters plugin available for Grails. Keep the User in session and verify in filter for each request..
Sample filter code:
class SecurityFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.user && !actionName.equals('login')) {
redirect(action: 'login')
return false
}
}
}
}
}
and specify the filter attributes..
Here is the documentation grails.org/doc/2.2.1/ref/Plug-ins/filters.html

How to discover all Entity Types? One of each?

I need to write a service that connects to CRM, and returns with a list of all of the entity available on the server (custom or otherwise).
How can I do this? To be clear, I am not looking to return all data for all entities. Just a list of every type, regardless of whether any actually exist.
You need to use RetrieveAllEntitiesRequest
RetrieveAllEntitiesRequest request = new RetrieveAllEntitiesRequest()
{
EntityFilters = EntityFilters.Entity,
RetrieveAsIfPublished = true
};
// service is the IOrganizationService
RetrieveAllEntitiesResponse response = (RetrieveAllEntitiesResponse)service.Execute(request);
foreach (EntityMetadata currentEntity in response.EntityMetadata)
{
string logicalName = currentEntity.LogicalName;
// your logic here
}
note that you will get also system or hidden entities, like wizardpage or recordcountsnapshot
You will probably find these sections of the MSDN useful:
Customize Entity Metadata (lookout for the samples linked on that page).
Retrieve and Detect Changes to Metadata.

Problem in implementing IAlertUpdateHandler interface

I've implemented IAlertUpdateHandler interface in a class and used it for handling creation and updating of alerts. The code is fired but it goes into endless loop by calling itself again and again.
Actually I want to suppress email notification so I'm calling a.Update(false); but this again calls PreUpdate or PostUpdate method and there is
StackOverFlowException :(
I've tried returning true/false from both the methods but nothing is helping.
According to the documentation, you're supposed to just return true or false. Try commenting out the Update call and just return either true or false. If you call Update, you'll just go into the recursive loop and your return statement will never get evaluated.
1
I know that it might be a bit late for this but I thought put it anyway to help the next one.
I found a solution/hack for this problem.
I beleive that when the alert is created from the UI the system fires an SPAlert.update(), so what I came up with is to do similar but ignore the update called from the UI to do that I added a custom property to the SPAlert property bag.
public bool PreUpdate(SPAlert a, SPWeb web, bool newAlert, string properties)
{
if (CHECK_IF_SUPPRESSING_EMAIL && !a.Properties.ContainsKey("CustomUpdate"))
{
//add a property to identify this update
a.Properties.Add("CustomUpdate", ""); //can be called anything :)
a.Update(false);
//return false to ignore the update sent by the UI
return false;
}
else
{
//no changes here proceed with custom behaviour
return true;
}
}
I have tested and it seems to do the trick hope this helps someone :)

Resources