com.sap.cds.feature.messaging.em.service.EnterpriseMessagingService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cds-feature-enterprise-messaging Show documentation
Show all versions of cds-feature-enterprise-messaging Show documentation
Enterprise Messaging feature for CDS Services Java
The newest version!
/**************************************************************************
* (C) 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
**************************************************************************/
package com.sap.cds.feature.messaging.em.service;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.regex.Pattern;
import org.apache.qpid.jms.message.JmsBytesMessage;
import org.apache.qpid.jms.message.JmsTextMessage;
import org.apache.qpid.jms.provider.amqp.message.AmqpJmsBytesMessageFacade;
import org.apache.qpid.jms.provider.amqp.message.AmqpJmsTextMessageFacade;
import com.sap.cds.feature.messaging.em.client.EnterpriseMessagingManagementClient;
import com.sap.cds.feature.messaging.em.jms.EnterpriseMessagingConnectionProvider;
import com.sap.cds.services.environment.CdsProperties.Messaging.MessagingServiceConfig;
import com.sap.cds.services.messaging.TopicMessageEventContext;
import com.sap.cds.services.messaging.jms.BrokerConnection;
import com.sap.cds.services.messaging.service.AbstractMessagingService;
import com.sap.cds.services.messaging.service.MessageQueue;
import com.sap.cds.services.messaging.service.MessageTopic;
import com.sap.cds.services.messaging.service.MessagingBrokerQueueListener;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.utils.StringUtils;
import com.sap.cloud.environment.servicebinding.api.ServiceBinding;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
/**
* Implementation of the enterprise messaging connector.
*/
public class EnterpriseMessagingService extends AbstractMessagingService {
private static final Pattern NAMESPACE_WILDCARD_PATTERN = Pattern.compile("([^/]*/[^/]*/[^/]*/)");
private static final String NAMESPACE_WILDCARD = "+/+/+/";
private static final String NAMESPACE_PLACEHOLDER = "$namespace";
protected final EnterpriseMessagingManagementClient managementClient;
private final EnterpriseMessagingConnectionProvider connectionProvider;
private final String queueNamespace;
private volatile BrokerConnection connection;
public EnterpriseMessagingService(MessagingServiceConfig serviceConfig, ServiceBinding binding, EnterpriseMessagingConnectionProvider connectionProvider, CdsRuntime runtime) {
super(resolveConfig(serviceConfig, getNamespaceFromBinding(binding)), runtime);
this.connectionProvider = connectionProvider; // might be null, e.g. mt scenario
this.managementClient = new EnterpriseMessagingManagementClient(binding);
this.queueNamespace = normalizeNamespace(getNamespaceFromBinding(binding));
}
private static String getNamespaceFromBinding(ServiceBinding binding) {
String namespace = (String) binding.getCredentials().get("namespace");
if (namespace != null) {
namespace = namespace.trim();
if (namespace.isEmpty()) {
namespace = null;
}
}
return namespace;
}
private static MessagingServiceConfig resolveConfig(MessagingServiceConfig serviceConfig, String namespace) {
if("cloudevents".equals(serviceConfig.getFormat())) {
if(serviceConfig.getSubscribePrefix() == null) {
serviceConfig.setSubscribePrefix(NAMESPACE_WILDCARD + "ce/");
}
if(serviceConfig.getPublishPrefix() == null) {
serviceConfig.setPublishPrefix(NAMESPACE_PLACEHOLDER + "/ce/");
}
}
String normalizedNamespace = normalizeNamespace(namespace);
if(serviceConfig.getSubscribePrefix() != null) {
serviceConfig.setSubscribePrefix(serviceConfig.getSubscribePrefix().replace(NAMESPACE_PLACEHOLDER, normalizedNamespace));
}
if(serviceConfig.getPublishPrefix() != null) {
serviceConfig.setPublishPrefix(serviceConfig.getPublishPrefix().replace(NAMESPACE_PLACEHOLDER, normalizedNamespace));
}
serviceConfig.getQueue().getConfig().entrySet().forEach(e -> {
if (e.getValue() instanceof String value && value.indexOf(NAMESPACE_PLACEHOLDER) != -1) {
e.setValue(value.replace(NAMESPACE_PLACEHOLDER, normalizedNamespace));
}
});
return serviceConfig;
}
private static String normalizeNamespace(String namespace) {
return namespace == null ? "" : StringUtils.trim(namespace.trim(), '/');
}
@Override
public void init() {
// create the broker connection asynchronously with topic subscriptions
connectionProvider.asyncConnectionInitialization(serviceConfig, connection -> {
this.connection = connection;
super.init();
});
}
@Override
public void stop() {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
// ignored
}
}
}
@Override
protected void removeQueue(String name) throws IOException {
managementClient.removeQueue(name);
}
@Override
protected void createQueue(String name, Map properties) throws IOException {
if (properties.containsKey("deadMsgQueue")) {
String dmQueue = (String) properties.get("deadMsgQueue");
if (managementClient.getQueue(dmQueue) == null) {
managementClient.createQueue(dmQueue, Collections.emptyMap());
}
}
managementClient.createQueue(name, properties);
}
@Override
protected void createQueueSubscription(String queue, String topic) throws IOException {
managementClient.createQueueSubscription(queue, topic);
}
@Override
protected void registerQueueListener(String queue, MessagingBrokerQueueListener listener) throws IOException {
connection.registerQueueListener("queue:" + queue, listener, m -> getMessageTopic(m));
}
@Override
protected void emitTopicMessage(String topic, TopicMessageEventContext messageEventContext) {
connection.emitTopicMessage("topic:" + topic, messageEventContext);
}
@Override
protected String toFullyQualifiedQueueName(MessageQueue queue) {
return queue.isFullyQualified() ? queue.getName().replace(NAMESPACE_PLACEHOLDER, queueNamespace) : queueNamespace + '/' + queue.getName();
}
@Override
protected String toFullyQualifiedTopicName(String event, boolean inbound) {
return super.toFullyQualifiedTopicName(isCloudEventsFormat() ? event.replace('.', '/') : event, inbound);
}
private String getMessageTopic(Message message) {
if (message instanceof JmsTextMessage textMessage) {
if (textMessage.getFacade() instanceof AmqpJmsTextMessageFacade textMessageFacade) {
return textMessageFacade.getType();
}
} else if (message instanceof JmsBytesMessage bytesMessage
&& bytesMessage.getFacade() instanceof AmqpJmsBytesMessageFacade bytesMessageFacade) {
return bytesMessageFacade.getType();
}
return null;
}
@Override
protected BiPredicate getTopicMatcher() {
return (internalTopic, brokerTopic) -> {
if (super.getTopicMatcher().test(internalTopic, brokerTopic)) {
return true;
}
if (internalTopic.getBrokerName().startsWith(NAMESPACE_WILDCARD)) {
String brokerTopicTail = NAMESPACE_WILDCARD_PATTERN.matcher(brokerTopic).replaceFirst("");
String internalTopicTail = internalTopic.getBrokerName().substring(NAMESPACE_WILDCARD.length());
if (brokerTopicTail.equals(internalTopicTail)) {
return true;
}
}
return false;
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy