use of io.github.microcks.domain.UnidirectionalEvent in project microcks by microcks.
the class AsyncMinionApp method onStart.
/**
* Application startup method.
*/
void onStart(@Observes StartupEvent ev) {
// We need to retrieve Keycloak server from Microcks config.
KeycloakConfig config = microcksAPIConnector.getKeycloakConfig();
logger.infof("Microcks Keycloak server url {%s} and realm {%s}", config.getAuthServerUrl(), config.getRealm());
String keycloakEndpoint = config.getAuthServerUrl() + "/realms/" + config.getRealm() + "/protocol/openid-connect/token";
if (!keycloakAuthURL.isEmpty() && keycloakAuthURL.get().length() > 0) {
logger.infof("Use locally defined Keycloak Auth URL: %s", keycloakAuthURL);
keycloakEndpoint = keycloakAuthURL.get() + "/realms/" + config.getRealm() + "/protocol/openid-connect/token";
}
try {
// First retrieve an authentication token before fetching async messages to publish.
String oauthToken;
if (config.isEnabled()) {
// We've got a full Keycloak config, attempt an authent.
oauthToken = keycloakConnector.connectAndGetOAuthToken(keycloakEndpoint);
logger.info("Authentication to Keycloak server succeed!");
} else {
// No realm config, probably a dev mode - use a fake token.
oauthToken = "<anonymous-admin-token>";
logger.info("Keycloak protection is not enabled, using a fake token");
}
int page = 0;
boolean fetchServices = true;
while (fetchServices) {
List<Service> services = microcksAPIConnector.listServices("Bearer " + oauthToken, page, SERVICES_FETCH_SIZE);
for (Service service : services) {
logger.debug("Found service " + service.getName() + " - " + service.getVersion());
if (service.getType().equals(ServiceType.EVENT)) {
// Find the operations matching this minion constraints..
List<Operation> operations = service.getOperations().stream().filter(o -> Arrays.asList(restrictedFrequencies).contains(o.getDefaultDelay())).filter(o -> o.getBindings().keySet().stream().anyMatch(Arrays.asList(supportedBindings)::contains)).collect(Collectors.toList());
if (operations.size() > 0) {
logger.info("Found " + operations.size() + " candidate operations in " + service.getName() + " - " + service.getVersion());
ServiceView serviceView = microcksAPIConnector.getService("Bearer " + oauthToken, service.getId(), true);
for (Operation operation : operations) {
AsyncMockDefinition mockDefinition = new AsyncMockDefinition(serviceView.getService(), operation, serviceView.getMessagesMap().get(operation.getName()).stream().filter(e -> e instanceof UnidirectionalEvent).map(e -> ((UnidirectionalEvent) e).getEventMessage()).collect(Collectors.toList()));
mockRepository.storeMockDefinition(mockDefinition);
schemaRegistry.updateRegistryForService(mockDefinition.getOwnerService());
}
}
}
}
if (services.size() < SERVICES_FETCH_SIZE) {
fetchServices = false;
}
page++;
}
logger.info("Starting scheduling of all producer jobs...");
producerScheduler.scheduleAllProducerJobs();
} catch (ConnectorException ce) {
logger.error("Cannot authenticate to Keycloak server and thus enable to call Microcks API" + "to get Async APIs to mocks...", ce);
throw new RuntimeException("Unable to start the Minion due to connection exception");
} catch (IOException ioe) {
logger.error("IOException while communicating with Keycloak or Microcks API", ioe);
throw new RuntimeException("Unable to start the Minion due to IO exception");
}
}
use of io.github.microcks.domain.UnidirectionalEvent in project microcks by microcks.
the class ServiceChangeEventPublisher method onApplicationEvent.
@Override
@Async
public void onApplicationEvent(ServiceChangeEvent event) {
log.debug("Received a ServiceChangeEvent on " + event.getServiceId());
ServiceView serviceView = null;
if (event.getChangeType() != ChangeType.DELETED) {
Service service = serviceRepository.findById(event.getServiceId()).orElse(null);
if (service != null) {
// Put messages into a map where key is operation name.
Map<String, List<? extends Exchange>> messagesMap = new HashMap<>();
for (Operation operation : service.getOperations()) {
if (service.getType() == ServiceType.EVENT) {
// If an event, we should explicitly retrieve event messages.
List<UnidirectionalEvent> events = messageService.getEventByOperation(IdBuilder.buildOperationId(service, operation));
messagesMap.put(operation.getName(), events);
} else {
// Otherwise we have traditional request / response pairs.
List<RequestResponsePair> pairs = messageService.getRequestResponseByOperation(IdBuilder.buildOperationId(service, operation));
messagesMap.put(operation.getName(), pairs);
}
}
serviceView = new ServiceView(service, messagesMap);
}
}
// Build and send a ServiceViewChangeEvent that wraps ServiceView.
ServiceViewChangeEvent serviceViewChangeEvent = new ServiceViewChangeEvent(event.getServiceId(), serviceView, event.getChangeType(), System.currentTimeMillis());
kafkaTemplate.send("microcks-services-updates", event.getServiceId(), serviceViewChangeEvent);
log.debug("Processing of ServiceChangeEvent done !");
}
use of io.github.microcks.domain.UnidirectionalEvent in project microcks by microcks.
the class AsyncAPIImporter method getMessageDefinitions.
@Override
public List<Exchange> getMessageDefinitions(Service service, Operation operation) throws MockRepositoryImportException {
List<Exchange> result = new ArrayList<>();
// Retrieve default content type, defaulting to application/json.
String defaultContentType = "application/json";
if (spec.has("defaultContentType")) {
defaultContentType = spec.get("defaultContentType").asText("application/json");
}
// Iterate on specification "channels" nodes.
Iterator<Entry<String, JsonNode>> channels = spec.path("channels").fields();
while (channels.hasNext()) {
Entry<String, JsonNode> channel = channels.next();
String channelName = channel.getKey();
Map<String, Map<String, String>> pathParametersByExample = extractParametersByExample(channel.getValue());
// Iterate on specification path, "verbs" nodes.
Iterator<Entry<String, JsonNode>> verbs = channel.getValue().fields();
while (verbs.hasNext()) {
Entry<String, JsonNode> verb = verbs.next();
String verbName = verb.getKey();
// Find the correct operation.
if (operation.getName().equals(verbName.toUpperCase() + " " + channelName.trim())) {
JsonNode messageBody = verb.getValue().path("message");
// If it's a $ref or multi-structure (oneOf, anyOf, allOf), then navigate to them.
List<JsonNode> messageBodies = followRefsIfAny(messageBody);
for (JsonNode extractedMsgBody : messageBodies) {
// Get message content type.
String contentType = defaultContentType;
if (extractedMsgBody.has("contentType")) {
contentType = extractedMsgBody.path("contentType").asText();
}
// No need to go further if no examples.
if (extractedMsgBody.has("examples")) {
Iterator<JsonNode> examples = extractedMsgBody.path("examples").elements();
int exampleIndex = 0;
while (examples.hasNext()) {
JsonNode exampleNode = examples.next();
EventMessage eventMessage = null;
if (exampleNode.has("name")) {
// As of AsyncAPI 2.1.0 () we can now have a 'name' property for examples!
eventMessage = extractFromAsyncAPI21Example(contentType, exampleNode);
} else if (exampleNode.has("payload")) {
// As of https://github.com/microcks/microcks/issues/385, we should support the restriction
// coming from AsyncAPI GItHub master revision and associated tooling...
eventMessage = extractFromAsyncAPIExample(contentType, exampleNode, channelName.trim() + "-" + exampleIndex);
} else {
eventMessage = extractFromMicrocksExample(contentType, exampleNode);
}
// add this event message as a valid event in results exchanges.
if (eventMessage != null) {
if (DispatchStyles.URI_PARTS.equals(operation.getDispatcher())) {
String resourcePathPattern = channelName;
Map<String, String> parts = pathParametersByExample.get(eventMessage.getName());
String resourcePath = URIBuilder.buildURIFromPattern(resourcePathPattern, parts);
operation.addResourcePath(resourcePath);
eventMessage.setDispatchCriteria(DispatchCriteriaHelper.buildFromPartsMap(parts));
}
result.add(new UnidirectionalEvent(eventMessage));
}
exampleIndex++;
}
}
}
}
}
}
return result;
}
use of io.github.microcks.domain.UnidirectionalEvent in project microcks by microcks.
the class AsyncMockDefinitionUpdater method onServiceUpdate.
@Incoming("microcks-services-updates")
public void onServiceUpdate(ServiceViewChangeEvent serviceViewChangeEvent) {
logger.info("Received a new change event [" + serviceViewChangeEvent.getChangeType() + "] for '" + serviceViewChangeEvent.getServiceId() + "', at " + serviceViewChangeEvent.getTimestamp());
// Remove existing definitions or add/update existing for EVENT services.
if (serviceViewChangeEvent.getChangeType().equals(ChangeType.DELETED)) {
logger.info("Removing mock definitions for " + serviceViewChangeEvent.getServiceId());
mockRepository.removeMockDefinitions(serviceViewChangeEvent.getServiceId());
schemaRegistry.clearRegistryForService(serviceViewChangeEvent.getServiceId());
} else {
// Only deal with service of type EVENT...
if (serviceViewChangeEvent.getServiceView() != null && serviceViewChangeEvent.getServiceView().getService().getType().equals(ServiceType.EVENT)) {
// Browse and check operation regarding restricted frequencies and supported bindings.
boolean scheduled = false;
for (Operation operation : serviceViewChangeEvent.getServiceView().getService().getOperations()) {
if (Arrays.asList(restrictedFrequencies).contains(operation.getDefaultDelay()) && operation.getBindings().keySet().stream().anyMatch(Arrays.asList(supportedBindings)::contains)) {
logger.info("Found '" + operation.getName() + "' as a candidate for async message mocking");
// Build an Async mock definition and store it into repository.
AsyncMockDefinition mockDefinition = new AsyncMockDefinition(serviceViewChangeEvent.getServiceView().getService(), operation, serviceViewChangeEvent.getServiceView().getMessagesMap().get(operation.getName()).stream().filter(e -> e instanceof UnidirectionalEvent).map(e -> ((UnidirectionalEvent) e).getEventMessage()).collect(Collectors.toList()));
mockRepository.storeMockDefinition(mockDefinition);
schemaRegistry.updateRegistryForService(mockDefinition.getOwnerService());
scheduled = true;
}
}
if (!scheduled) {
logger.info("Ensure to un-schedule " + serviceViewChangeEvent.getServiceId() + " on this minion. Removing definitions.");
mockRepository.removeMockDefinitions(serviceViewChangeEvent.getServiceId());
schemaRegistry.clearRegistryForService(serviceViewChangeEvent.getServiceId());
}
}
}
}
use of io.github.microcks.domain.UnidirectionalEvent in project microcks by microcks.
the class ServiceController method getService.
@RequestMapping(value = "/services/{id:.+}", method = RequestMethod.GET)
public ResponseEntity<?> getService(@PathVariable("id") String serviceId, @RequestParam(value = "messages", required = false, defaultValue = "true") boolean messages) {
log.debug("Retrieving service with id {}", serviceId);
Service service = null;
// serviceId may have the form of <service_name>:<service_version>
if (serviceId.contains(":")) {
String name = serviceId.substring(0, serviceId.indexOf(':'));
String version = serviceId.substring(serviceId.indexOf(':') + 1);
// If service name was encoded with '+' instead of '%20', replace them.
if (name.contains("+")) {
name = name.replace('+', ' ');
}
service = serviceRepository.findByNameAndVersion(name, version);
} else {
service = serviceRepository.findById(serviceId).orElse(null);
}
if (messages) {
// Put messages into a map where key is operation name.
Map<String, List<? extends Exchange>> messagesMap = new HashMap<>();
for (Operation operation : service.getOperations()) {
if (service.getType() == ServiceType.EVENT) {
// If an event, we should explicitly retrieve event messages.
List<UnidirectionalEvent> events = messageService.getEventByOperation(IdBuilder.buildOperationId(service, operation));
messagesMap.put(operation.getName(), events);
} else {
// Otherwise we have traditional request / response pairs.
List<RequestResponsePair> pairs = messageService.getRequestResponseByOperation(IdBuilder.buildOperationId(service, operation));
messagesMap.put(operation.getName(), pairs);
}
}
return new ResponseEntity<>(new ServiceView(service, messagesMap), HttpStatus.OK);
}
return new ResponseEntity<>(service, HttpStatus.OK);
}
Aggregations