What's a Thead in FOSMessageBundle - multithreading

I don't understand what the thread class is in FOSMessageBundle (https://github.com/FriendsOfSymfony/FOSMessageBundle).
Could you explain what it represents?

A thread is like a conversation, it contains a list of messages between the same participants.
A close look at the model class will help you understand how it works:
A thread contains a collection of Messages as well as
important Metadata about the thread.
/**
* Messages contained in this thread.
*
* #var Collection|MessageInterface[]
*/
protected $messages;
/**
* Thread metadata.
*
* #var Collection|ThreadMetadata[]
*/
protected $metadata;
/**
* Users participating in this conversation.
*
* #var Collection|ParticipantInterface[]
*/
protected $participants;

a thread contains message of different participants, like a forum

Related

DelayHandler messageGroupId

From the Spring Integration documentation (https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#delayer) it is not clear to me what the messageGroupId in the DelayHandler means exactly and which value I have to set there exactly (is it arbitrary?). This value does not exist in the xml configuration, but does in the Java configuration.
#ServiceActivator(inputChannel = "input")
#Bean
public DelayHandler delayer() {
DelayHandler handler = new DelayHandler("delayer.messageGroupId"); // THIS constructor parameter is not clear to me
handler.setDefaultDelay(3_000L);
handler.setDelayExpressionString("headers['delay']");
handler.setOutputChannelName("output");
return handler;
}
It is explained in the JavaDocs of that constructor:
/**
* Create a DelayHandler with the given 'messageGroupId' that is used as 'key' for
* {#link MessageGroup} to store delayed Messages in the {#link MessageGroupStore}.
* The sending of Messages after the delay will be handled by registered in the
* ApplicationContext default
* {#link org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler}.
* #param messageGroupId The message group identifier.
* #see #getTaskScheduler()
*/
public DelayHandler(String messageGroupId) {
It is not required because the groupId is based on the required id attribute:
String id = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error("The 'id' attribute is required.", element);
}
...
builder.addConstructorArgValue(id + ".messageGroupId");
It is really mentioned and explained a little bit in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#delayer-namespace.
The value indeed is arbitrary, but it must be unique per your application, so different delayers don't steal messages from each other.

Spring Integration DSL: Transformer using headers

I want to use Java DSL for Spring Integration, but I can't figure out how to use message headers during transformation.
My old implementation had a Transformer like this:
#Transformer(inputChannel = "inputChannel", outputChannel = "outputChannel")
public EventB transform(
EventA eventA,
#Header("a_header") String aHeader,
#Header("other_header") String otherHeader){
return new EventB(eventA.getSomeField(), aHeader, otherHeader);
}
Now I have the following DSL:
#Bean
public IntegrationFlow aFlow(){
return IntegrationFlows.from(EventASink.INPUT)
.filter("headers['operation'] == 'OPERATION_A'")
.transform() //<-- What should I do here?
.handle(Http.outboundGateway(uri).httpMethod(HttpMethod.POST))
.get();
}
I looked at the implementation of transform() method and I found that it can receive a GenericTransformer as parameter, but it seems to work only with message payload and I also need the headers.
I also saw that some kind of reflection can be used, but I don't like it because its not refactor-safe.
Any advice? Thanks in advance.
Since the DSL is a part of the Framework and it is compiled before you start to use it, we can't infer any custom POJO methods, therefore there is no so clean way to count with any custom headers like in your sample.
The closet way to re-use your transform() with those annotations on parameters is with this .transform() contract:
/**
* Populate the {#code MessageTransformingHandler} for the {#link MethodInvokingTransformer}
* to invoke the service method at runtime.
* #param service the service to use.
* #param methodName the method to invoke.
* #return the current {#link IntegrationFlowDefinition}.
* #see MethodInvokingTransformer
*/
public B transform(Object service, String methodName)
So, you would need to declare a bean with that method and use it in the service argument meanwhile mention the method in the methodName argument.
Another way to get access to headers is to request the whole Message type for lambda:
/**
* Populate the {#link MessageTransformingHandler} instance for the provided
* {#link GenericTransformer} for the specific {#code payloadType} to convert at
* runtime.
* Use {#link #transform(Class, GenericTransformer)} if you need access to the
* entire message.
* #param payloadType the {#link Class} for expected payload type. It can also be
* {#code Message.class} if you wish to access the entire message in the transformer.
* Conversion to this type will be attempted, if necessary.
* #param genericTransformer the {#link GenericTransformer} to populate.
* #param <P> the payload type - 'transform from' or {#code Message.class}.
* #param <T> the target type - 'transform to'.
* #return the current {#link IntegrationFlowDefinition}.
* #see MethodInvokingTransformer
* #see LambdaMessageProcessor
*/
public <P, T> B transform(Class<P> payloadType, GenericTransformer<P, T> genericTransformer) {
In this case the code could be like this:
.transform(Message.class, m -> m.getHeaders())
I had the same issue. I needed both headers and payload. After a lot of tinkering I found a solution. I used .handle instead of .transform. GenericHandler's handle method provides both payload and headers.
In your case it would look something like:
#Bean
public IntegrationFlow aFlow(){
return IntegrationFlows.from(EventASink.INPUT)
.filter("headers['operation'] == 'OPERATION_A'")
.<EventA>handle((eventA, h) -> new EventB(
eventA.getSomeField(),
h.get("a_header", String.class),
h.get("other_header", String.class)))
.handle(Http.outboundGateway(uri).httpMethod(HttpMethod.POST))
.get();
}

int:gateway equivalent Java DSL

What is the Java DSL equivalent for int:gateway which has error channel and a default request channel.
The default request channel is input to a transformer which sends JMS message to outbound adaptor and returns a listenable future.
Something like this:
return IntegrationFlows.from(Gate.class)
/**
* Populate the {#link MessageChannel} to the new {#link IntegrationFlowBuilder}
* chain, which becomes as a {#code requestChannel} for the Messaging Gateway(s) built
* on the provided service interface.
* <p>A gateway proxy bean for provided service interface is registered under a name
* from the
* {#link org.springframework.integration.annotation.MessagingGateway#name()} if present
* or from the {#link IntegrationFlow} bean name plus {#code .gateway} suffix.
* #param serviceInterface the service interface class with an optional
* {#link org.springframework.integration.annotation.MessagingGateway} annotation.
* #return new {#link IntegrationFlowBuilder}.
*/
public static IntegrationFlowBuilder from(Class<?> serviceInterface) {
https://docs.spring.io/spring-integration/docs/current/reference/html/java-dsl.html#java-dsl-gateway

File::load in drupal8 custom module controller

i have created one custom module, in the controller file i used File::load static method. but when I'm run phpcs for check coding standards it will give an error as
File::load calls should be avoided in classes, use dependency injection instead
anyone can please tell how to create dependency injection for this.
The be achieved by using Drupal\Core\Entity\EntityTypeManagerInterface.
use Drupal\Core\Entity\EntityTypeManagerInterface;
class MyForm extends FormBase {
/**
* The storage handler class for files.
*
* #var \Drupal\file\FileStorage
*/
protected $fileStorage;
/**
* This is an example.
*
* #param \Drupal\Core\Entity\EntityTypeManagerInterface $entity
* The Entity type manager service.
*/
public function __construct(EntityTypeManagerInterface $entity) {
$this->fileStorage = $entity->getStorage('file');
}
....
}
From there you can update the File::load($fid) to $this->fileStorage->load($fid)

Is there a way to make the #Builder annotation work for immutable classes?

I'm trying to develop a project in Groovy and I've been looking through my code and trying to find areas which I could replace with something more idiomatically Groovy until I find a solution for another issue I've been having.
I've started taking a more in-depth look into the use of AST transformation annotations - they've helped significantly cut down on the amount of code I have to write in some places. However, I'm having an issue using the groovy.transform.builder.Builder annotation with one of my immutable value classes. The source for this annotation is hosted here.
The issue is that the annotation seems to make the builder set the values of the buildee directly rather than storing a copy of the values and passing them to the buildee's constructor. This results in a ReadOnlyPropertyException when you try to use it with immutable classes.
There are four possible Builder strategies you can select with this annotation, and of them I've tried DefaultStrategy, ExternalStrategy and InitializerStrategy. However, all of these have caused problems.
ExternalStrategy looks like the most promising of the four, and you can find an SSCCE based on it detailing the problem here.
The source code from the example is also included below:
import groovy.transform.Immutable
import groovy.transform.builder.Builder as GBuilder
import groovy.transform.builder.ExternalStrategy
/*
* Uncommenting the below causes a failure:
* 'groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: value for class: Value'
*/
//#Immutable
class Value {
#GBuilder(forClass = Value, prefix = 'set', builderStrategy = ExternalStrategy)
static class Builder { }
int value
String toString() { "Value($value)" }
}
def builder = new Value.Builder()
println builder.setValue(1).build()
There also seems to be a relevant JIRA discussion on the matter here.
Edit
I've tried using CFrick's answer below, using InitializerStrategy rather than ExternalStrategy.
Everything now compiles, but I get the following errors at run-time when I try to execute my tests:
java.lang.IllegalAccessError: tried to access class com.github.tagc.semver.version.BaseVersion from class com.github.tagc.semver.version.BaseVersion$com.github.tagc.semver.version.BaseVersionInitializer
at java.lang.Class.getDeclaringClass(Class.java:1227)
at java.beans.MethodRef.set(MethodRef.java:46)
at java.beans.MethodDescriptor.setMethod(MethodDescriptor.java:117)
at java.beans.MethodDescriptor.<init>(MethodDescriptor.java:72)
at java.beans.MethodDescriptor.<init>(MethodDescriptor.java:56)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1163)
at java.beans.Introspector.getBeanInfo(Introspector.java:426)
at java.beans.Introspector.getBeanInfo(Introspector.java:173)
at com.github.tagc.semver.version.VersionFactory.createBaseVersion(VersionFactory.groovy:34)
at com.github.tagc.semver.test.util.TestSetup.<clinit>(TestSetup.groovy:77)
at java.lang.Class.forName(Class.java:344)
at com.github.tagc.semver.version.SnapshotDecoratorSpec.#decoratedVersion should be considered equal to patch-bumped #releaseVersion snapshot(SnapshotDecoratorSpec.groovy:24)
Followed thereafter by a series of exceptions like the following:
java.lang.NoClassDefFoundError: Could not initialize class com.github.tagc.semver.test.util.TestSetup
at java.lang.Class.forName(Class.java:344)
at com.github.tagc.semver.version.SnapshotDecoratorSpec.#decoratedVersion should be considered equal to minor-bumped #releaseVersion snapshot(SnapshotDecoratorSpec.groovy:36)
What I have right now is a BaseVersion class like the following:
/**
* A concrete, base implementation of {#link com.github.tagc.semver.version.Version Version}.
*
* #author davidfallah
* #since v0.1.0
*/
#Immutable
#Builder(prefix = 'set', builderStrategy = InitializerStrategy)
#PackageScope
final class BaseVersion implements Version {
// ...
/**
* The major category of this version.
*/
int major = 0
/**
* The minor category of this version.
*/
int minor = 0
/**
* The patch category of this version.
*/
int patch = 0
/**
* Whether this version is a release or snapshot version.
*/
boolean release = false
// ...
}
A factory to produce instances of these:
/**
* A factory for producing base and decorated {#code Version} objects.
*
* #author davidfallah
* #since v0.5.0
*/
class VersionFactory {
// ...
/**
* Returns an instance of {#link com.github.tagc.semver.version.BaseVersion BaseVersion} constructed
* with the given parameters.
*
* #param major the major category value of the version instance
* #param minor the minor category value of the version instance
* #param patch the patch category value of the version instance
* #param release the release setting of the version instance
* #return an instance of {#code BaseVersion}
*/
static BaseVersion createBaseVersion(int major, int minor, int patch, boolean release) {
return new BaseVersion(major, minor, patch, release)
}
/**
* Returns an instance of {#link com.github.tagc.semver.version.BaseVersion BaseVersion} constructed
* with the given parameters.
*
* #param m a map of parameter names and their corresponding values corresponding to the
* construction parameters of {#code BaseVersion}.
*
* #return an instance of {#code BaseVersion}
*/
static BaseVersion createBaseVersion(Map m) {
return new BaseVersion(m)
}
/**
* Returns an instance of {#link com.github.tagc.semver.version.BaseVersion BaseVersion} constructed
* with the given parameters.
*
* #param l a list of parameter values corresponding to the construction parameters of {#code BaseVersion}.
*
* #return an instance of {#code BaseVersion}
*/
static BaseVersion createBaseVersion(List l) {
return new BaseVersion(l)
}
/**
* Returns a builder for {#link com.github.tagc.semver.version.BaseVersion BaseVersion} to specify
* the construction parameters for the {#code BaseVersion} incrementally.
*
* #return an instance of {#code BaseVersion.Builder}
*/
static Object createBaseVersionBuilder() {
return BaseVersion.builder()
}
// ...
}
A test specification class for Version objects:
/**
* Test specification for {#link com.github.tagc.semver.version.Version Version}.
*
* #author davidfallah
* #since 0.1.0
*/
#Unroll
class VersionSpec extends Specification {
static exampleVersions = [
VersionFactory.createBaseVersion(major:1, minor:2, patch:3),
VersionFactory.createBaseVersion(major:0, minor:0, patch:0),
VersionFactory.createBaseVersion(major:5, minor:4, patch:3),
VersionFactory.createBaseVersion(major:1, minor:16, patch:2),
VersionFactory.createBaseVersion(major:4, minor:5, patch:8),
]
// ...
}
And other classes that try to create instances of BaseVersion that are failing, such as TestSetup.
Your code there fails, because chosen strategy there basically does:
def v = new Value().with{ setValue(1); return it }
and this can not be done on #Immutable objects.
According to the docs, there is only InitializerStrategy, that can explicitly cope with #Immutable.
You can use the InitializerStrategy in conjunction with #Canonical and #Immutable. If your #Builder annotation doesn’t have explicit includes or excludes annotation attributes but your #Canonical annotation does, the ones from #Canonical will be re-used for #Builder.
E.g.
import groovy.transform.*
import groovy.transform.builder.*
#Immutable
#ToString
#Builder(prefix='set', builderStrategy=InitializerStrategy)
class Value {
int value
}
def builder = Value.createInitializer().setValue(1)
assert new Value(builder).toString()=='Value(1)'
Depending on what you are up to, this is rahter ugly syntax and you might be better off just using the Map-based c'tors. Even without e.g. #TypeChecked a new Value(vlaue: 666) will generate an error and leaving params (for a class with multiple properties) will leave them null.

Resources