Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding IBMMQ Discovery Agent #148

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ The Event Management Agent comes with the following event or message broker plug
* Solace PubSub+
* Confluent Schema Registry
* MSK
* IBM MQ

The default application.yml provides various plugin examples. For Kafka, the properties section under credentials is passthrough. For example a property in ConsumerConfig or SSLConfigs classes.

Expand Down
5 changes: 5 additions & 0 deletions service/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@
<artifactId>terraform-plugin</artifactId>
<version>1.6.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.solace.maas.plugin.ibmmq</groupId>
<artifactId>ibmmq-plugin</artifactId>
<version>1.6.1-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>io.micrometer</groupId>
Expand Down
18 changes: 18 additions & 0 deletions service/application/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,21 @@ eventPortal:
# value: software.amazon.msk.auth.iam.IAMLoginModule required;
# - name: sasl.client.callback.handler.class
# value: software.amazon.msk.auth.iam.IAMClientCallbackHandler
# # IBM MQ Example
# - id: ibmmqDefaultService
# type: IBMMQ
# name: IBM MQ Test Service
# connections:
# - name: IBMMQBroker
# url: ${ADMINISTRATOR_REST_ENDPOINT_URL}
# authentication:
# - protocol: BASIC
# credentials:
# - source: ENVIRONMENT_VARIABLE
# properties:
# - name: username
# value: ${IBMMQ_ADMINISTRATOR_USERNAME}
# - name: password
# value: ${IBMMQ_ADMINISTRATOR_PASSWORD}
# operations:
# - name: IBMMQ_ALL
80 changes: 80 additions & 0 deletions service/ibmmq-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.solace.maas.plugin.ibmmq</groupId>
<artifactId>ibmmq-plugin</artifactId>
<version>1.6.1-SNAPSHOT</version>
<name>Solace Event Management Agent - IBM MQ Plugin</name>
<description>Solace Event Management Agent - IBM MQ Plugin</description>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<solace.maas.ema.version>1.6.1-SNAPSHOT</solace.maas.ema.version>
<spring.boot.version>3.1.7</spring.boot.version>
<spring.cloud.openfeign.version>4.1.0</spring.cloud.openfeign.version>
<openfeign.jackson.version>13.0</openfeign.jackson.version>
<okhttp.version>4.0.1</okhttp.version>
<camel.version>4.2.0</camel.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring.cloud.openfeign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>${openfeign.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.solace.maas</groupId>
<artifactId>plugin</artifactId>
<version>${solace.maas.ema.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>${camel.version}</version>
</dependency>

<!-- TESTING -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>${okhttp.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class IbmMqApplication {

public static void main(String[] args) {
SpringApplication.run(IbmMqApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
* Interface for OpenFeign to create the IBM MQ REST API Admin Client.
*/
@FeignClient(name = "ibmmq-http-client")
public interface IbmMqHttpClient {

/*Gets all queues on a given queue manager*/
@GetMapping("/queue")
IbmMqQueueResponse getQueues();

/*Gets all subscriptions (topics) on a given queue manager*/
@GetMapping("/subscription")
IbmMqSubscriptionResponse getSubscriptions();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http;

import com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor.event.IbmMqQueueEvent;
import lombok.Getter;

import java.util.List;

/**
* Represents the response JSON from the IBM MQ Admin client
* when querying for Queue information.
*/
@Getter
public class IbmMqQueueResponse {

private List<IbmMqQueueEvent> queue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http;

import com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor.event.IbmMqSubscriptionEvent;
import lombok.Data;

import java.util.List;

/**
* Represents the response JSON from the IBM MQ Admin client
* when querying for Subscription (topic) information.
*/
@Data
public class IbmMqSubscriptionResponse {

List<IbmMqSubscriptionEvent> subscription;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.manager.client;

import com.solace.maas.ep.event.management.agent.plugin.manager.client.MessagingServiceClientConfig;
import org.springframework.context.annotation.Configuration;

@Configuration
public class IbmMqClientConfigImpl extends MessagingServiceClientConfig {

private static final String SERVICE_NAME = "IBMMQ";

protected IbmMqClientConfigImpl() {
super(SERVICE_NAME, new IbmMqClientManagerImpl());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.manager.client;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http.IbmMqHttpClient;
import com.solace.maas.ep.event.management.agent.plugin.manager.client.MessagingServiceClientManager;
import com.solace.maas.ep.event.management.agent.plugin.messagingService.event.AuthenticationDetailsEvent;
import com.solace.maas.ep.event.management.agent.plugin.messagingService.event.ConnectionDetailsEvent;
import com.solace.maas.ep.event.management.agent.plugin.util.MessagingServiceConfigurationUtil;
import feign.Feign;
import feign.auth.BasicAuthRequestInterceptor;
import feign.jackson.JacksonDecoder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.stereotype.Component;

import java.util.NoSuchElementException;

/**
* Implementation of the IBM MQ Administration client.
* <p>
* This client provides access to the various administrative endpoints exposed by IBM MQ.
*/
@Slf4j
@Data
@Component
public class IbmMqClientManagerImpl implements MessagingServiceClientManager<IbmMqHttpClient> {

public IbmMqClientManagerImpl() {
}

@Override
public IbmMqHttpClient getClient(ConnectionDetailsEvent connectionDetailsEvent) {

log.trace("Creating IBM MQ RESTful client for event broker [{}].",
connectionDetailsEvent.getMessagingServiceId());

//get authentication details from config file
AuthenticationDetailsEvent authenticationDetailsEvent = connectionDetailsEvent.getAuthenticationDetails()
.stream()
.findFirst().orElseThrow(() -> {
String message = String.format("Could not find authentication details for service with id [%s].",
connectionDetailsEvent.getMessagingServiceId());
log.error(message);
return new NoSuchElementException(message);
});

String username = MessagingServiceConfigurationUtil.getUsername(authenticationDetailsEvent);
String password = MessagingServiceConfigurationUtil.getPassword(authenticationDetailsEvent);
String url = connectionDetailsEvent.getUrl();

/*so that we can configure Jackson to ignore unknown properties in the
response json.
*/
ObjectMapper mapper = JsonMapper
.builder()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.build();

return Feign.builder()
.requestInterceptor(new BasicAuthRequestInterceptor(username, password))
.contract(new SpringMvcContract())
.decoder(new JacksonDecoder(mapper))
.target(IbmMqHttpClient.class, url);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor;

import com.solace.maas.ep.event.management.agent.plugin.constants.RouteConstants;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http.IbmMqHttpClient;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http.IbmMqQueueResponse;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor.event.IbmMqQueueEvent;
import com.solace.maas.ep.event.management.agent.plugin.processor.base.ResultProcessorImpl;
import com.solace.maas.ep.event.management.agent.plugin.service.MessagingServiceDelegateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class IbmMqQueueProcessor extends ResultProcessorImpl<List<IbmMqQueueEvent>, Void> {
private final MessagingServiceDelegateService messagingServiceDelegateService;

@Autowired
public IbmMqQueueProcessor(MessagingServiceDelegateService messagingServiceDelegateService) {
super();
this.messagingServiceDelegateService = messagingServiceDelegateService;
}

@Override
public List<IbmMqQueueEvent> handleEvent(Map<String, Object> properties, Void body) throws Exception {
String messagingServiceId = (String) properties.get(RouteConstants.MESSAGING_SERVICE_ID);

IbmMqHttpClient client = messagingServiceDelegateService.getMessagingServiceClient(messagingServiceId);

log.info("### Invoking Queue endpoint for broker with ID {}", messagingServiceId);
IbmMqQueueResponse queueList = client.getQueues();

return queueList.getQueue();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor;

import com.solace.maas.ep.event.management.agent.plugin.constants.RouteConstants;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http.IbmMqHttpClient;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.client.http.IbmMqSubscriptionResponse;
import com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor.event.IbmMqSubscriptionEvent;
import com.solace.maas.ep.event.management.agent.plugin.processor.base.ResultProcessorImpl;
import com.solace.maas.ep.event.management.agent.plugin.service.MessagingServiceDelegateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class IbmMqSubscriptionProcessor extends ResultProcessorImpl<List<IbmMqSubscriptionEvent>, Void> {
private final MessagingServiceDelegateService messagingServiceDelegateService;

@Autowired
public IbmMqSubscriptionProcessor(MessagingServiceDelegateService messagingServiceDelegateService) {
super();
this.messagingServiceDelegateService = messagingServiceDelegateService;
}

@Override
public List<IbmMqSubscriptionEvent> handleEvent(Map<String, Object> properties, Void body) throws Exception {
String messagingServiceId = (String) properties.get(RouteConstants.MESSAGING_SERVICE_ID);

IbmMqHttpClient client = messagingServiceDelegateService.getMessagingServiceClient(messagingServiceId);

log.info("### Invoking Queue endpoint for broker with ID {}", messagingServiceId);
IbmMqSubscriptionResponse subscriptionList = client.getSubscriptions();

return subscriptionList.getSubscription();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.solace.maas.ep.event.management.agent.plugin.ibmmq.processor.event;

import lombok.Getter;

import java.io.Serializable;

/**
* Attributes parsed from the response JSON.
* Note: Other attributes may be returned in the raw JSON.
*/
@Getter
public class IbmMqQueueEvent implements Serializable {

private static final long serialVersionUID = 7693606299215131178L;

private String name;
private String type;
}
Loading