Why we can set only destination type(Queue name) in message driven bean? - ejb-3.0

Why We can set only single destination type in message driven bean in EJB?
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "FileProcess"),
#ActivationConfigProperty(propertyName = "transactionTimeout", propertyValue = "3600"),
#ActivationConfigProperty(propertyName = "maxSession", propertyValue = "100") })
#TransactionManagement(value = TransactionManagementType.CONTAINER)
public class FileMDB implements MessageListener {
//.....
}
I want to add more than one destination type for a single MSD , Can i add more than one queue name or destination type in a MDB class?

The short answer is: because Sun (and JSR expert groups) designed it that way.
The longer answer: I'm guessing that you need to handle many queues which all contain messages of the same format, and it does not matter to your service where the message came from. You can:
Implement a base class implementing MessageListener interface and inherit from it as many times as you wish, each time applying different #ActivationConfigProperty annotation.
(a better option) If your messaging system allows, create an extra queue and configure all the queues that are of interest to your application to pass messages to that queue. Then you can stay with your current MDB configuration, without the need to produce boilerplate code.

Related

Publish multiple events shares some attributes in one kafka topic

I need to publish multiple messages from the same project which represents employee journey events, and i need to use one topic only to publish these messages as they are representing the same project, but in some cases the message may contain extra fields for example:
All messages share (id, name, type, date) and
may some events have more fields like (course id, course name), so I am intending to use one parent object called "Journey", contains "Event" object, and I will create multiple children objects like 'LMSEvent' that extends this Event, etc if needed. Also using the Jackson + spring boot over rest APIs to do the needed cast based on type attribute. Finally, then this message to Kafka directly, so, each object contains its own properties.
For the consumer, I will do some strategy patterns and do the required logic per each type if needed.
The message size will not be very big and i don't expect to have more different attributes per each event.
I am looking to know if this approach is good or not and in case is not, what is the alternative.
I think that in general it is good approach. Having single message schema on topic or multiple schemas is always good question and both has some bright sights and drawbacks, you can read more about it in Martin Kleppmann article.
When you decided to have multiple events on single topic, starting from rest api and next by Kafka producer and consumer you can use the same approach of serializing and deserializing events, #JsonTypeInfo and #JsonSubTypes does the job:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = LMSEvent.class, name = "LMSEvent"),
#JsonSubTypes.Type(value = YetAnotherEvent.class, name = "YetAnotherEvent")
})
public interface Event {
String getType();
default boolean hasType(String type) {
return getType().equalsIgnoreCase(type);
}
default <T> T getConcreteEvent(Class<T> clazz) {
return clazz.cast(this);
}
}
When you consume that type of messages using spring-kafka you can define some very neat code, where each method is consuming concrete event type, so you don't need to write some dirty casting by your own:
#KafkaListener(topics = "someEvents", containerFactory = "myKafkaContainerFactory")
public class MyKafkaHandler {
#KafkaHandler
void handleLMSEvent(LMSEvent event) {
....
}
#KafkaHandler
void handleYetAnotherEvent(YetAnotherEvent yetAnotherEvent) {
...
}
#KafkaHandler(isDefault = true)
void handleDefault(#Payload Object unknown,
#Header(KafkaHeaders.OFFSET) long offset,
#Header(KafkaHeaders.RECEIVED_PARTITION) int partitionId,
#Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
logger.info("Server received unknown message {},{},{}", offset, partitionId, topic);
}
}
Full code

SpringBoot RabbitMQ - how to reduce boilerplate for many topics (events)?

I wonder if there is a way to reduce amount of boilerplate code when initializing many RabbitMQ queues/bindings in SpringBoot?
Following event-driven approach, my app produces like 50 types of events (it will be split into several smaller apps later, but still).
Each event goes to exchange with type "topic".
Some events are getting consumed by other apps, some events additionally consumed by the same app which is sending them.
Lets consider that publishing-and-self-consuming case.
In SpringBoot for each event I need to declare:
routing key name in config (like "event.item.purchased")
queue name to consume that event inside the same app
("queue.event.item.purchased")
matching configuration properties class field or a variable itemPurchasedRoutingKey or constant in code which keeps property name (like ${event.item.purchased})
bean for Queue creation (with a name featuring event name) like
itemPurchasedQueue
bean for Binding creation (with a name featuring
event name) and routing key name. like itemPurchasedBinding which is
constructed with itemPurchasedQueue.bind(...itemPurchasedRoutingKey)
RabbitListener for event, with annotation containing queue name
(can't be defined in runtime)
So - 6 places where "item purchased" is mentioned in one or another form.
The amount of boilerplate code is just killing me :)
If there are 50 events, its very easy to make a mistake - when adding new event, you need to remember to add it to 6 places.
Ideally, for each event I'd like to:
specify routing key in config. Queue name can be built upon it by appending common prefix (specific to the app).
use some annotation or alternative RabbitListener which automatically declares queue (by routing key + prefix), binds to it, and listens to events.
Is there a way to optimize it?
I thought about custom annotations, but RabbitListener doesn't like dynamic queue names, and spring boot can't find beans for queues and bindings if I declare them inside some util method.
Maybe there is a way to declare all that stuff in code, but it's not a Spring way, I believe :)
So I ended up using manual bean declaration and using 1 bind() method for each bean
#Configuration
#EnableConfigurationProperties(RabbitProperties::class)
class RabbitConfiguration(
private val properties: RabbitProperties,
private val connectionFactory: ConnectionFactory
) {
#Bean
fun admin() = RabbitAdmin(connectionFactory)
#Bean
fun exchange() = TopicExchange(properties.template.exchange)
#Bean
fun rabbitMessageConverter() = Jackson2JsonMessageConverter(
jacksonObjectMapper()
.registerModule(JavaTimeModule())
.registerModule(Jdk8Module())
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
)
#Value("\${okko.rabbit.queue-prefix}")
lateinit var queuePrefix: String
fun <T> bind(routingKey: String, listener: (T) -> Mono<Void>): SimpleMessageListenerContainer {
val queueName = "$queuePrefix.$routingKey"
val queue = Queue(queueName)
admin().declareQueue(queue)
admin().declareBinding(BindingBuilder.bind(queue).to(exchange()).with(routingKey)!!)
val container = SimpleMessageListenerContainer(connectionFactory)
container.addQueueNames(queueName)
container.setMessageListener(MessageListenerAdapter(MessageHandler(listener), rabbitMessageConverter()))
return container
}
internal class MessageHandler<T>(private val listener: (T) -> Mono<Void>) {
// NOTE: don't change name of this method, rabbit needs it
fun handleMessage(message: T) {
listener.invoke(message).subscribeOn(Schedulers.elastic()).subscribe()
}
}
}
#Service
#Configuration
class EventConsumerRabbit(
private val config: RabbitConfiguration,
private val routingKeys: RabbitEventRoutingKeyConfig
) {
#Bean
fun event1() = handle(routingKeys.event1)
#Bean
fun event2() = handle(routingKeys.event2)
...
private fun<T> handle(routingKey: String): Mono<Void> = config.bind<T>(routingKey) {
log.debug("consume rabbit event: $it")
... // handle event, return Mono<Void>
}
companion object {
private val log by logger()
}
}
#Configuration
#ConfigurationProperties("my.rabbit.routing-key.event")
class RabbitEventRoutingKeyConfig {
lateinit var event1: String
lateinit var event2: String
...
}

Does spring kafka support auto-deserialization in consumer side with no explicit type provided?

I'm using spring-integration-kafka.
I have an abstract interface Event, which has dozens of concrete implementations, say, AEvent, BEvent, CEvent, etc.. And I want one only consumer listener to handle all incoming Events, such as fun handle(message: Message<>) { message.payload... }
After reading the documentation, I find no way to support auto-deserialization with no explicit type provided in consumer side.
Any suggestion will be appreciated.
Using JdkSerializationRedisSerializer from spring-data-redis meet my requirements.
public class GenericObjectSerializer implements Serializer<Object> {
private final JdkSerializationRedisSerializer serializer =
new JdkSerializationRedisSerializer();
}
public class GenericObjectDeserializer implements Deserializer<Object> {
private final JdkSerializationRedisSerializer serializer =
new JdkSerializationRedisSerializer();
}

OSGi how to run mutliple instances of one service

Is it possible to run multiple instance of the same service in the osgi framework?
More specific, I need to start multiple instances of a service, but each instance should recieve different parameters. This is because the services have similar functionality. But instead of writing a service for every variation, I want to reuse one implementing class.
I've already found the registerService method in the framework api.
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
however, i seem to create only one instance of each class. Is there a workaround for this?
preferably something like
ServiceRegistration<?> registration = bundlecontext.registerService(
className + "#" + (++counter), new classInstance(), null);
Note that using Declarative Services with the corresponding annotations makes this quite easy, here's an excerpt from the Apache Sling codebase (ConfiguredFeature.java):
#Component(
name = "org.apache.sling.featureflags.Feature",
metatype = true,
configurationFactory = true,
policy = ConfigurationPolicy.REQUIRE)
#Service
public class ConfiguredFeature implements Feature {
#Property(label = "Name", description = "Short name of this feature")
private static final String NAME = "name";
private String name;
#Activate
private void activate(final Map<String, Object> configuration) {
this.name = PropertiesUtil.toString(configuration.get(NAME), "");
}
...
}
Using configurationFactory = true and policy = ConfigurationPolicy.REQUIRE causes one instance of this service to be created for each corresponding OSGi configuration, which is a natural way of creating multiple instances.
You could create a ManagedServiceFactory. The factory can register a new service for each configuration set in Configuration Admin.
I have a simple example here which uses Felix DependencyManager to register the component: https://github.com/paulbakker/osgicourse/tree/master/greeterfactory/src/greeterfactory
You have the parameters slightly wrong, or at least misleading:
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
The second parameter to registerService is an object, not a class. This is an object you instantiate yourself. You can create as many as you like, in whatever way you like, before passing them to OSGi.
However if you are doing this with externally-supplied configuration data, should look into Declarative Services and their ability to receive config from the OSGi Configuration Admin service.
UPDATE
Taking another look at your question, I see the counter that you tried to add to the class name. This is not required and in fact not permitted either. Just call registerService multiple times.

Annotation endpoint Location for JAX-WS

does exist a specific annotation to define the address of the endpoint.
In fact, I want to remove the attribute address in the SPring file and move the annotation directly in the impl. class.
Current:
jaxws:endpoint id="dataManagerEndPoint" implementor="#dataManagerService" address="/datamanager/v1.0"
#WebService
public interface DataManagerService
I would like to change to (if possible) ...
jaxws:endpoint id="dataManagerEndPoint" implementor="#dataManagerService"
#WebService
#EndPointAddress ("/datamanager/v1.0")
public interface DataManagerService
Many thanks, in advance,
Christophe P.
#WebService(portName = "PortTypeName", serviceName = "ServiceName", targetNamespace = "http://www.namespace.com", wsdlLocation = "META-INF/wsdlname.wsdl", endpointInterface = "com.package.service.PortTypeName")

Resources