Search in sources :

Example 1 with Exchange

use of io.github.microcks.domain.Exchange 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 !");
}
Also used : RequestResponsePair(io.github.microcks.domain.RequestResponsePair) ServiceView(io.github.microcks.domain.ServiceView) ServiceViewChangeEvent(io.github.microcks.event.ServiceViewChangeEvent) HashMap(java.util.HashMap) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) Service(io.github.microcks.domain.Service) MessageService(io.github.microcks.service.MessageService) Operation(io.github.microcks.domain.Operation) Exchange(io.github.microcks.domain.Exchange) List(java.util.List) Async(org.springframework.scheduling.annotation.Async)

Example 2 with Exchange

use of io.github.microcks.domain.Exchange in project microcks by microcks.

the class PostmanCollectionImporter method getMessageDefinitionsV2.

private List<Exchange> getMessageDefinitionsV2(Service service, Operation operation) {
    Map<Request, Response> result = new HashMap<Request, Response>();
    Iterator<JsonNode> items = collection.path("item").elements();
    while (items.hasNext()) {
        JsonNode item = items.next();
        result.putAll(getMessageDefinitionsV2("", item, operation));
    }
    // Adapt map to list of Exchanges.
    return result.entrySet().stream().map(entry -> new RequestResponsePair(entry.getKey(), entry.getValue())).collect(Collectors.toList());
}
Also used : Response(io.github.microcks.domain.Response) java.util(java.util) JsonGenerator(com.fasterxml.jackson.core.JsonGenerator) LoggerFactory(org.slf4j.LoggerFactory) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) DispatchCriteriaHelper(io.github.microcks.util.DispatchCriteriaHelper) TypeFactory(com.fasterxml.jackson.databind.type.TypeFactory) Exchange(io.github.microcks.domain.Exchange) MockRepositoryImporter(io.github.microcks.util.MockRepositoryImporter) JsonNode(com.fasterxml.jackson.databind.JsonNode) Resource(io.github.microcks.domain.Resource) Parameter(io.github.microcks.domain.Parameter) Response(io.github.microcks.domain.Response) DispatchStyles(io.github.microcks.util.DispatchStyles) MockRepositoryImportException(io.github.microcks.util.MockRepositoryImportException) Request(io.github.microcks.domain.Request) URIBuilder(io.github.microcks.util.URIBuilder) Logger(org.slf4j.Logger) PatternSyntaxException(java.util.regex.PatternSyntaxException) Files(java.nio.file.Files) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) Service(io.github.microcks.domain.Service) Header(io.github.microcks.domain.Header) Operation(io.github.microcks.domain.Operation) ServiceType(io.github.microcks.domain.ServiceType) Paths(java.nio.file.Paths) JsonWriteFeature(com.fasterxml.jackson.core.json.JsonWriteFeature) RequestResponsePair(io.github.microcks.domain.RequestResponsePair) RequestResponsePair(io.github.microcks.domain.RequestResponsePair) Request(io.github.microcks.domain.Request) JsonNode(com.fasterxml.jackson.databind.JsonNode)

Example 3 with Exchange

use of io.github.microcks.domain.Exchange 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;
}
Also used : ArrayList(java.util.ArrayList) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) JsonNode(com.fasterxml.jackson.databind.JsonNode) Exchange(io.github.microcks.domain.Exchange) Entry(java.util.Map.Entry) EventMessage(io.github.microcks.domain.EventMessage) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with Exchange

use of io.github.microcks.domain.Exchange 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);
}
Also used : RequestResponsePair(io.github.microcks.domain.RequestResponsePair) ServiceView(io.github.microcks.domain.ServiceView) HashMap(java.util.HashMap) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) MessageService(io.github.microcks.service.MessageService) ServiceService(io.github.microcks.service.ServiceService) Service(io.github.microcks.domain.Service) Operation(io.github.microcks.domain.Operation) Exchange(io.github.microcks.domain.Exchange) ResponseEntity(org.springframework.http.ResponseEntity) List(java.util.List)

Example 5 with Exchange

use of io.github.microcks.domain.Exchange in project microcks by microcks.

the class ServiceService method importServiceDefinition.

/**
 * Import definitions of services and bounded resources and messages into Microcks
 * repository. This uses a MockRepositoryImporter under hood.
 * @param repositoryFile The File for mock repository.
 * @param referenceResolver The Resolver to be used during import (may be null).
 * @param artifactInfo The essential information on Artifact to import.
 * @return The list of imported Services
 * @throws MockRepositoryImportException if something goes wrong (URL not reachable nor readable, etc...)
 */
public List<Service> importServiceDefinition(File repositoryFile, ReferenceResolver referenceResolver, ArtifactInfo artifactInfo) throws MockRepositoryImportException {
    // Retrieve the correct importer based on file path.
    MockRepositoryImporter importer = null;
    try {
        importer = MockRepositoryImporterFactory.getMockRepositoryImporter(repositoryFile, referenceResolver);
    } catch (IOException ioe) {
        log.error("Exception while accessing file " + repositoryFile.getPath(), ioe);
        throw new MockRepositoryImportException(ioe.getMessage(), ioe);
    }
    Service reference = null;
    boolean serviceUpdate = false;
    List<Service> services = importer.getServiceDefinitions();
    for (Service service : services) {
        Service existingService = serviceRepository.findByNameAndVersion(service.getName(), service.getVersion());
        log.debug("Service [{}, {}] exists ? {}", service.getName(), service.getVersion(), existingService != null);
        // If it's the main artifact: retrieve previous id and props if update, save anyway.
        if (artifactInfo.isMainArtifact()) {
            if (existingService != null) {
                // Retrieve its previous identifier and metadatas
                // (backup metadata that may have been imported with extensions).
                Metadata backup = service.getMetadata();
                service.setId(existingService.getId());
                service.setMetadata(existingService.getMetadata());
                // If there was metadata found through extensions, overwrite historical ones.
                if (backup != null) {
                    existingService.getMetadata().setLabels(backup.getLabels());
                    existingService.getMetadata().setAnnotations(backup.getAnnotations());
                }
                // Keep its overriden operation properties.
                copyOverridenOperations(existingService, service);
                serviceUpdate = true;
            }
            if (service.getMetadata() == null) {
                service.setMetadata(new Metadata());
            }
            // For services of type EVENT, we should put default values on frequency and bindings.
            if (service.getType().equals(ServiceType.EVENT)) {
                manageEventServiceDefaults(service);
            }
            service.getMetadata().objectUpdated();
            service.setSourceArtifact(artifactInfo.getArtifactName());
            service = serviceRepository.save(service);
            // We're dealing with main artifact so reference is saved or updated one.
            reference = service;
        } else {
            // It's a secondary artifact just for messages or metadata. We'll have problems if not having an existing service...
            if (existingService == null) {
                log.warn("Trying to import {} as a secondary artifact but there's no existing [{}, {}] Service. Just skipping.", artifactInfo.getArtifactName(), service.getName(), service.getVersion());
                break;
            }
            // update the existing service with them.
            if (service.getMetadata() != null) {
                existingService.getMetadata().setLabels(service.getMetadata().getLabels());
                existingService.getMetadata().setAnnotations(service.getMetadata().getAnnotations());
            }
            for (Operation operation : service.getOperations()) {
                Operation existingOp = existingService.getOperations().stream().filter(op -> op.getName().equals(operation.getName())).findFirst().orElse(null);
                if (existingOp != null) {
                    if (operation.getDefaultDelay() != null) {
                        existingOp.setDefaultDelay(operation.getDefaultDelay());
                    }
                    if (operation.getDispatcher() != null) {
                        existingOp.setDispatcher(operation.getDispatcher());
                    }
                    if (operation.getDispatcherRules() != null) {
                        existingOp.setDispatcherRules(operation.getDispatcherRules());
                    }
                }
            }
            // We're dealing with secondary artifact so reference is the pre-existing one.
            // Moreover, we should replace current imported service (unbound/unsaved)
            // by reference in the results list.
            reference = existingService;
            services.remove(service);
            services.add(reference);
        }
        // Remove resources previously attached to service.
        List<Resource> existingResources = resourceRepository.findByServiceIdAndSourceArtifact(reference.getId(), artifactInfo.getArtifactName());
        if (existingResources != null && existingResources.size() > 0) {
            resourceRepository.deleteAll(existingResources);
        }
        // Save new resources.
        List<Resource> resources = importer.getResourceDefinitions(service);
        for (Resource resource : resources) {
            resource.setServiceId(reference.getId());
            resource.setSourceArtifact(artifactInfo.getArtifactName());
        }
        resourceRepository.saveAll(resources);
        for (Operation operation : reference.getOperations()) {
            String operationId = IdBuilder.buildOperationId(reference, operation);
            // Remove messages previously attached to service.
            requestRepository.deleteAll(requestRepository.findByOperationIdAndSourceArtifact(operationId, artifactInfo.getArtifactName()));
            responseRepository.deleteAll(responseRepository.findByOperationIdAndSourceArtifact(operationId, artifactInfo.getArtifactName()));
            eventMessageRepository.deleteAll(eventMessageRepository.findByOperationIdAndSourceArtifact(operationId, artifactInfo.getArtifactName()));
            List<Exchange> exchanges = importer.getMessageDefinitions(service, operation);
            for (Exchange exchange : exchanges) {
                if (exchange instanceof RequestResponsePair) {
                    RequestResponsePair pair = (RequestResponsePair) exchange;
                    // Associate request and response with operation and artifact.
                    pair.getRequest().setOperationId(operationId);
                    pair.getResponse().setOperationId(operationId);
                    pair.getRequest().setSourceArtifact(artifactInfo.getArtifactName());
                    pair.getResponse().setSourceArtifact(artifactInfo.getArtifactName());
                    // Save response and associate request with response before saving it.
                    responseRepository.save(pair.getResponse());
                    pair.getRequest().setResponseId(pair.getResponse().getId());
                    requestRepository.save(pair.getRequest());
                } else if (exchange instanceof UnidirectionalEvent) {
                    UnidirectionalEvent event = (UnidirectionalEvent) exchange;
                    // Associate event message with operation and artifact before saving it..
                    event.getEventMessage().setOperationId(operationId);
                    event.getEventMessage().setSourceArtifact(artifactInfo.getArtifactName());
                    eventMessageRepository.save(event.getEventMessage());
                }
            }
        }
        // When extracting message information, we may have modified Operation because discovered new resource paths
        // depending on variable URI parts. As a consequence, we got to update Service in repository.
        serviceRepository.save(reference);
        // Publish a Service update event before returning.
        publishServiceChangeEvent(reference, serviceUpdate ? ChangeType.UPDATED : ChangeType.CREATED);
    }
    log.info("Having imported {} services definitions into repository", services.size());
    return services;
}
Also used : RequestResponsePair(io.github.microcks.domain.RequestResponsePair) Metadata(io.github.microcks.domain.Metadata) Resource(io.github.microcks.domain.Resource) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) Service(io.github.microcks.domain.Service) MockRepositoryImporter(io.github.microcks.util.MockRepositoryImporter) IOException(java.io.IOException) Operation(io.github.microcks.domain.Operation) MockRepositoryImportException(io.github.microcks.util.MockRepositoryImportException) Exchange(io.github.microcks.domain.Exchange)

Aggregations

Exchange (io.github.microcks.domain.Exchange)5 Operation (io.github.microcks.domain.Operation)4 RequestResponsePair (io.github.microcks.domain.RequestResponsePair)4 Service (io.github.microcks.domain.Service)4 UnidirectionalEvent (io.github.microcks.domain.UnidirectionalEvent)4 HashMap (java.util.HashMap)3 JsonNode (com.fasterxml.jackson.databind.JsonNode)2 Resource (io.github.microcks.domain.Resource)2 ServiceView (io.github.microcks.domain.ServiceView)2 MessageService (io.github.microcks.service.MessageService)2 MockRepositoryImportException (io.github.microcks.util.MockRepositoryImportException)2 MockRepositoryImporter (io.github.microcks.util.MockRepositoryImporter)2 IOException (java.io.IOException)2 List (java.util.List)2 JsonGenerator (com.fasterxml.jackson.core.JsonGenerator)1 JsonWriteFeature (com.fasterxml.jackson.core.json.JsonWriteFeature)1 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 TypeFactory (com.fasterxml.jackson.databind.type.TypeFactory)1 EventMessage (io.github.microcks.domain.EventMessage)1