diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml index 8a349d3d..5b50257e 100644 --- a/.github/workflows/update-version.yml +++ b/.github/workflows/update-version.yml @@ -18,6 +18,7 @@ jobs: run: | echo "Updating to version: $(jq -r '.pull_request.milestone.title' $GITHUB_EVENT_PATH)" mvn versions:set -DnewVersion=$(jq -r '.pull_request.milestone.title' $GITHUB_EVENT_PATH) + mvn pom.xml versions:set-property -Dproperty=assimbly.version -DnewVersion=$(jq -r '.pull_request.milestone.title' $GITHUB_EVENT_PATH) - name: Diff check run: git diff diff --git a/bin/mac/updateversion.sh b/bin/mac/updateversion.sh index 2e7af2b7..c8f7ca96 100755 --- a/bin/mac/updateversion.sh +++ b/bin/mac/updateversion.sh @@ -1,3 +1,5 @@ +#!/bin/bash + if [ -n "$1" ]; then printf "\nupdate version to: $1\n" mvn -f ../../pom.xml versions:set -DgenerateBackupPoms=false -DnewVersion="$1" diff --git a/dil/src/main/java/org/assimbly/dil/blocks/processors/FailureProcessor.java b/dil/src/main/java/org/assimbly/dil/blocks/processors/FailureProcessor.java index 72f09c91..016244a9 100644 --- a/dil/src/main/java/org/assimbly/dil/blocks/processors/FailureProcessor.java +++ b/dil/src/main/java/org/assimbly/dil/blocks/processors/FailureProcessor.java @@ -16,7 +16,7 @@ import org.apache.camel.spi.Language; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; -import org.assimbly.dil.event.FlowEvent; +import org.assimbly.dil.event.domain.FlowEvent; import org.assimbly.util.BaseDirectory; import javax.xml.xpath.XPathFactory; diff --git a/dil/src/main/java/org/assimbly/dil/event/EventCollector.java b/dil/src/main/java/org/assimbly/dil/event/EventCollector.java deleted file mode 100644 index 39bbd157..00000000 --- a/dil/src/main/java/org/assimbly/dil/event/EventCollector.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.assimbly.dil.event; - -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.EventObject; -import java.util.List; - -import org.apache.camel.impl.event.ExchangeFailedEvent; -import org.apache.camel.impl.event.ExchangeFailureHandledEvent; -import org.apache.camel.impl.event.RouteStartedEvent; -import org.apache.camel.impl.event.RouteStoppedEvent; -import org.apache.camel.spi.CamelEvent; -import org.apache.camel.support.EventNotifierSupport; -import org.apache.commons.io.FileUtils; -import org.assimbly.util.BaseDirectory; - -//Check following page for all EventObject instances: http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/management/event/package-summary.html - -public class EventCollector extends EventNotifierSupport { - - private final String baseDir = BaseDirectory.getInstance().getBaseDirectory(); - private Date date = new Date(); - private String error; - private String today = new SimpleDateFormat("yyyyMMdd").format(date); - private String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:SS Z").format(date); - - public void notify(EventObject eventObject) throws Exception { - - if (eventObject instanceof RouteStartedEvent) { - - RouteStartedEvent routeStartedEvent = (RouteStartedEvent) eventObject; - String flowId = routeStartedEvent.getRoute().getId(); - File file = new File(baseDir + "/events/" + flowId + "/" + today + "_events.log"); - List line = Arrays.asList(timestamp + " : flow started"); - FileUtils.writeLines(file, line, true); - - }else if (eventObject instanceof RouteStoppedEvent) { - - RouteStoppedEvent routeStoppedEvent = (RouteStoppedEvent) eventObject; - String flowId = routeStoppedEvent.getRoute().getId(); - File file = new File(baseDir + "/events/" + flowId + "/" + today + "_events.log"); - List line = Arrays.asList(timestamp + " : flow stopped"); - FileUtils.writeLines(file, line, true); - - - }else if (eventObject instanceof ExchangeFailedEvent) { - - ExchangeFailedEvent exchangeFailedEvent = (ExchangeFailedEvent) eventObject; - String flowId = exchangeFailedEvent.getExchange().getFromRouteId(); - String exchangeId = exchangeFailedEvent.getExchange().getExchangeId(); - - Throwable cause = exchangeFailedEvent.getExchange().getException(); - - if(cause!=null) { - error = "Message " + exchangeId + " failed. error=" + cause.getMessage(); - }else { - error = "Message " + exchangeId + " failed. (check gateway log for error details)"; - } - - - error = exchangeFailedEvent.getExchange().getException().getMessage(); - File file = new File(baseDir + "/events/" + flowId + "/" + today + "_events.log"); - List line = Arrays.asList(timestamp + " : flow error (unhandled) --> " + error); - FileUtils.writeLines(file, line, true); - - }else if (eventObject instanceof ExchangeFailureHandledEvent) { - - ExchangeFailureHandledEvent exchangeFailedEvent = (ExchangeFailureHandledEvent) eventObject; - String flowId = exchangeFailedEvent.getExchange().getFromRouteId(); - String exchangeId = exchangeFailedEvent.getExchange().getExchangeId(); - String deadLetterUri = exchangeFailedEvent.getDeadLetterUri(); - - Throwable cause = exchangeFailedEvent.getExchange().getException(); - - if(cause!=null) { - error = "Message " + exchangeId + " is sent to error step: " + deadLetterUri + " error=" + cause.getMessage(); - }else { - error = "Message " + exchangeId + " is sent to error step: " + deadLetterUri + " (check gateway log for error details)"; - } - - File file = new File(baseDir + "/events/" + flowId + "/" + today + "_events.log"); - List line = Arrays.asList(timestamp + " : flow error --> " + error); - FileUtils.writeLines(file, line, true); - - } - - } - - public boolean isEnabled(EventObject event) { - return true; - } - - protected void doStart() throws Exception { - // noop - } - - protected void doStop() throws Exception { - // noop - } - - @Override - public void notify(CamelEvent event) throws Exception { - // TODO Auto-generated method stub - } - -} diff --git a/dil/src/main/java/org/assimbly/dil/event/EventConfigurer.java b/dil/src/main/java/org/assimbly/dil/event/EventConfigurer.java new file mode 100644 index 00000000..f5804326 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/EventConfigurer.java @@ -0,0 +1,227 @@ +package org.assimbly.dil.event; + +import ch.qos.logback.classic.Level; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.camel.CamelContext; +import org.apache.camel.spi.EventNotifier; +import org.assimbly.dil.event.collect.MessageCollector; +import org.assimbly.dil.event.collect.LogCollector; +import org.assimbly.dil.event.collect.StepCollector; +import org.assimbly.dil.event.domain.Collection; +import org.assimbly.dil.event.domain.Filter; +import org.assimbly.dil.event.domain.Store; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ch.qos.logback.classic.LoggerContext; + +import java.util.ArrayList; + + +public class EventConfigurer { + + protected Logger log = LoggerFactory.getLogger(getClass()); + + private CamelContext context; + + private String collectorId; + + private Collection configuration; + private String type; + + public EventConfigurer(String collectorId, CamelContext context) { + this.collectorId = collectorId; + this.context = context; + } + + public String checkConfiguration(String jsonConfiguration) { + + try { + configuration = new Collection().fromJson(jsonConfiguration); + } catch (JsonProcessingException e) { + return e.getMessage(); + } + + if(configuration == null){ + return "Invalid event format (json)"; + } + + type = configuration.getType(); + + if(type==null){ + return "Event type is missing. Valid types are message,log and step."; + }else if(!type.equals("log") && !type.equals("message") && !type.equals("step")){ + return "Invalid event collector: " + type + ". Valid types are message,log and step."; + } + + String id = configuration.getId(); + + if(!this.collectorId.equals(id)){ + return "CollectorId of endpoint and configuration don't match. CollectorId endpoint=" + collectorId + " and CollectorID configuration=" + id; + } + + //remove if configuration already exists + if(isConfigured()){ + remove(collectorId); + } + + return "ok"; + + } + + public String add(String jsonConfiguration) { + + String checkMessage = checkConfiguration(jsonConfiguration); + + if(!checkMessage.equals("ok")){ + return checkMessage; + }else{ + + try { + + switch (type) { + case "message": + configureMessageCollector(); + break; + case "step": + configureStepCollector(); + break; + case "log": + configureLogCollector(); + break; + } + } catch (Exception e){ + return e.getMessage(); + } + + return "configured"; + + } + } + + + public String remove(String collectorId) { + + log.info("Removing collector with id=" + collectorId); + + Object collector = context.getRegistry().lookupByName(collectorId); + + if(collector instanceof MessageCollector){ + ((MessageCollector) collector).shutdown(); + context.getManagementStrategy().removeEventNotifier((EventNotifier)collector); + log.info("Removed message collector with id=" + collectorId); + }else if(collector instanceof StepCollector){ + ((StepCollector) collector).shutdown(); + context.getManagementStrategy().removeEventNotifier((EventNotifier)collector); + log.info("Removed step collector with id=" + collectorId); + }else if(collector instanceof LogCollector ){ + LogCollector logCollector = (LogCollector) collector; + removeLogger(logCollector); + log.info("Removed log collector with id=" + collectorId); + }else{ + log.warn("Collector with id=" + collectorId + " does not exist"); + } + + return "removed"; + } + + public boolean isConfigured(){ + Object collector = context.getRegistry().lookupByName(collectorId); + if(collector==null){ + return false; + }else{ + return true; + } + } + + + public void configureStepCollector() { + + log.info("Configure collection of step events"); + String id = configuration.getId(); + ArrayList events = configuration.getEvents(); + ArrayList filters = configuration.getFilters(); + ArrayList stores = configuration.getStores(); + + StepCollector stepCollector = new StepCollector(id, events, filters, stores); + stepCollector.setIgnoreCamelContextEvents(true); + stepCollector.setIgnoreCamelContextInitEvents(true); + stepCollector.setIgnoreExchangeEvents(true); + stepCollector.setIgnoreServiceEvents(true); + stepCollector.setIgnoreStepEvents(true); + + context.getManagementStrategy().addEventNotifier(stepCollector); + context.getRegistry().bind(id, stepCollector); + } + + public void configureMessageCollector() { + + log.info("Configure collection of message events"); + + String id = configuration.getId(); + ArrayList events = configuration.getEvents(); + ArrayList filters = configuration.getFilters(); + ArrayList stores = configuration.getStores(); + + MessageCollector messageCollector = new MessageCollector(id, events, filters, stores); + messageCollector.setIgnoreCamelContextEvents(true); + messageCollector.setIgnoreCamelContextInitEvents(true); + messageCollector.setIgnoreRouteEvents(true); + messageCollector.setIgnoreServiceEvents(true); + messageCollector.setIgnoreStepEvents(true); + + context.getManagementStrategy().addEventNotifier(messageCollector); + context.getRegistry().bind(id, messageCollector); + + } + + public void configureLogCollector() { + + log.info("Configure collection of log events"); + + String id = configuration.getId(); + String tag = "LOG"; + ArrayList events = configuration.getEvents(); + ArrayList filters = configuration.getFilters(); + ArrayList stores = configuration.getStores(); + + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + + LogCollector logCollector = new LogCollector(id, tag, events, filters, stores); + logCollector.setContext(loggerContext); + logCollector.setName(collectorId); + logCollector.start(); + + ArrayList packageNames = configuration.getEvents(); + + for(String packageName: packageNames){ + addLogger(logCollector, packageName, "info"); + } + + context.getRegistry().bind(id, logCollector); + + } + + private void addLogger(LogCollector logCollector, String packageName, String logLevel){ + + ch.qos.logback.classic.Logger logbackLogger = null; + + if(packageName.equalsIgnoreCase("all") || packageName.equalsIgnoreCase("root")){ + logbackLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + }else{ + logbackLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName); + } + + //setAdditive to true, so that it's treated as an additional log (log is kept in the main log file) + logbackLogger.setAdditive(true); + logbackLogger.setLevel(Level.toLevel(logLevel)); + logbackLogger.addAppender(logCollector); + + } + + private void removeLogger(LogCollector logCollector){ + logCollector.stop(); + ch.qos.logback.classic.Logger logbackLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(logCollector.getName()); + logbackLogger.detachAppender(logCollector.getName()); + } + +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/event/collect/LogCollector.java b/dil/src/main/java/org/assimbly/dil/event/collect/LogCollector.java new file mode 100644 index 00000000..8ca61f2f --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/collect/LogCollector.java @@ -0,0 +1,66 @@ +package org.assimbly.dil.event.collect; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +import org.assimbly.dil.event.domain.Filter; +import org.assimbly.dil.event.domain.LogEvent; +import org.assimbly.dil.event.store.StoreManager; +import org.assimbly.dil.event.util.EventUtil; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; + + +public class LogCollector extends AppenderBase { + + private final StoreManager storeManager; + private final String collectorId; + private final String tag; + private final ArrayList filters; + + + public LogCollector(String collectorId, String tag, ArrayList events, ArrayList filters, ArrayList stores) { + this.collectorId = collectorId; + this.tag = tag; + this.filters = filters; + this.storeManager = new StoreManager(collectorId, stores); + } + + + @Override + protected void append(Object o) { + + LoggingEvent event = (LoggingEvent) o; + if(event!=null){ + + String message = event.getMessage(); + + if(filters==null){ + processEvent(event, message); + }else if(EventUtil.isFiltered(filters, message)){ + processEvent(event, message); + } + + } + } + + private void processEvent(LoggingEvent event, String message){ + + //set fields + String timestamp = EventUtil.getTimestamp(); + String logLevel = event.getLevel().toString(); + String exception = (logLevel.equalsIgnoreCase("error")) ? message : ""; + + //create json + LogEvent logEvent = new LogEvent(timestamp, collectorId, logLevel, tag, message, exception); + String json = logEvent.toJson(); + + //store the event + storeManager.storeEvent(json); + + } + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/collect/MessageCollector.java b/dil/src/main/java/org/assimbly/dil/event/collect/MessageCollector.java new file mode 100644 index 00000000..f736743e --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/collect/MessageCollector.java @@ -0,0 +1,112 @@ +package org.assimbly.dil.event.collect; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.builder.ExpressionBuilder; +import org.apache.camel.spi.CamelEvent; +import org.apache.camel.support.EventNotifierSupport; +import org.assimbly.dil.event.domain.Filter; +import org.assimbly.dil.event.domain.Store; +import org.assimbly.dil.event.store.StoreManager; +import org.assimbly.dil.event.util.EventUtil; +import org.assimbly.dil.event.domain.MessageEvent; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +//Check following page for all Event instances: https://www.javadoc.io/doc/org.apache.camel/camel-api/latest/org/apache/camel/spi/CamelEvent.html + +public class MessageCollector extends EventNotifierSupport { + + private final StoreManager storeManager; + private final String expiryInHours; + private final ArrayList filters; + private final ArrayList events; + + public MessageCollector(String collectorId, ArrayList events, ArrayList filters, ArrayList stores) { + this.events = events; + this.filters = filters; + this.storeManager = new StoreManager(collectorId, stores); + List elasticStores = stores.stream().filter(p -> p.getType().equals("elastic")).collect(Collectors.toList()); + if(elasticStores.size()==1){ + this.expiryInHours = elasticStores.get(0).getExpiryInHours(); + }else{ + this.expiryInHours = "8"; + } + } + + + @Override + public void notify(CamelEvent event) throws Exception { + + String type = event.getType().name(); + + //filter only the configured events + if(events!=null && events.contains(type)) { + + //Cast to exchange event + CamelEvent.ExchangeEvent exchangeEvent = (CamelEvent.ExchangeEvent) event; + + //Get the message exchange from exchange event + Exchange exchange = exchangeEvent.getExchange(); + + //get the stepid + String stepId = ExpressionBuilder.routeIdExpression().evaluate(exchange, String.class); + + //process and store the exchange + if(stepId!=null && filters==null){ + processEvent(exchange, stepId); + }else if(stepId!=null && EventUtil.isFiltered(filters, stepId)){ + processEvent(exchange, stepId); + } + + } + + } + + private void processEvent(Exchange exchange, String stepId){ + + //set fields + Message message = exchange.getMessage(); + String body = getBody(message); + Map headers = message.getHeaders(); + String messageId = message.getMessageId(); + String timestamp = EventUtil.getTimestamp(); + + //create json + MessageEvent messageEvent = new MessageEvent(timestamp, messageId, stepId, "0", stepId, headers, body, expiryInHours); + String json = messageEvent.toJson(); + + //store the event + storeManager.storeEvent(json); + } + + public String getBody(Message message) { + + try { + + byte[] body = message.getBody(byte[].class); + + if (body == null) { + return ""; + }else if (body.length == 0) { + return ""; + }if (!(message.getBody() instanceof String)) { + String typeName = message.getBody().getClass().getTypeName(); + return "<" + typeName + ">"; + }else if (body.length > 250000) { + return new String(Arrays.copyOfRange(body, 0, 250000)); + }else{ + return new String (body); + } + + } catch (Exception e) { + return ""; + } + + } + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/collect/StepCollector.java b/dil/src/main/java/org/assimbly/dil/event/collect/StepCollector.java new file mode 100644 index 00000000..abf4166a --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/collect/StepCollector.java @@ -0,0 +1,73 @@ +package org.assimbly.dil.event.collect; + +import org.apache.camel.spi.CamelEvent; +import org.apache.camel.support.EventNotifierSupport; +import org.assimbly.dil.event.domain.Filter; +import org.assimbly.dil.event.domain.StepEvent; +import org.assimbly.dil.event.store.StoreManager; +import org.assimbly.dil.event.util.EventUtil; + +import java.text.SimpleDateFormat; +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +//Check following page for all Event instances: https://www.javadoc.io/doc/org.apache.camel/camel-api/latest/org/apache/camel/spi/CamelEvent.html + +public class StepCollector extends EventNotifierSupport { + + private final ArrayList filters; + private final ArrayList events; + private final StoreManager storeManager; + + public StepCollector(String collectorId, ArrayList events, ArrayList filters, ArrayList stores) { + this.events = events; + this.filters = filters; + this.storeManager = new StoreManager(collectorId, stores); + + } + + @Override + public void notify(CamelEvent event) throws Exception { + + String type = event.getType().name(); + + if(event instanceof CamelEvent.RouteEvent && events!=null && events.contains(type)) { + + //Cast to route event + CamelEvent.RouteEvent routeEvent = (CamelEvent.RouteEvent) event; + + //Set stepId from route + String stepId = routeEvent.getRoute().getId(); + + //process and store the exchange + if(stepId!=null && filters==null){ + processEvent(routeEvent, stepId); + }else if(stepId!=null && EventUtil.isFiltered(filters, stepId)){ + processEvent(routeEvent, stepId); + } + + } + + } + + private void processEvent(CamelEvent.RouteEvent routeEvent, String stepId){ + + //set fields + String timestamp = EventUtil.getTimestamp(); + String logLevel = "INFO"; + String message = "Step " + stepId + " " + routeEvent.getType().name().substring(5); + String exception = ""; + + //create json + StepEvent stepEvent = new StepEvent(timestamp, stepId, logLevel, "STEP", message, exception); + String json = stepEvent.toJson(); + + //store event + storeManager.storeEvent(json); + } + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/Collection.java b/dil/src/main/java/org/assimbly/dil/event/domain/Collection.java new file mode 100644 index 00000000..cffc0dd0 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/Collection.java @@ -0,0 +1,81 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.io.IOException; +import java.util.ArrayList; + +public class Collection { + + private static final ObjectMapper mapper = new ObjectMapper(); + private String id; + private String type; + private ArrayList events; + private ArrayList stores; + private ArrayList filters; + + @JsonProperty("id") + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + @JsonProperty("type") + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + @JsonProperty("events") + public ArrayList getEvents() { + return this.events; + } + + public void setEvents(ArrayList events) { + this.events = events; + } + + @JsonProperty("stores") + public ArrayList getStores() { + return this.stores; + } + + public void setStores(ArrayList stores) { + this.stores = stores; + } + + @JsonProperty("filters") + public ArrayList getFilters() { + return this.filters; + } + + public void setFilters(ArrayList filters) { + this.filters = filters; + } + + public Collection fromJson(String json) throws JsonProcessingException { + + Collection myObject = mapper.readValue(json, Collection.class); + + return myObject; + } + + public String toJson() { + mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + + try { + return mapper.writeValueAsString(this); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/Filter.java b/dil/src/main/java/org/assimbly/dil/event/domain/Filter.java new file mode 100644 index 00000000..cbbc1bcb --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/Filter.java @@ -0,0 +1,27 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Filter{ + private String id; + private String filter; + + @JsonProperty("id") + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + @JsonProperty("filter") + public String getFilter() { + return this.filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/FlowEvent.java b/dil/src/main/java/org/assimbly/dil/event/domain/FlowEvent.java similarity index 94% rename from dil/src/main/java/org/assimbly/dil/event/FlowEvent.java rename to dil/src/main/java/org/assimbly/dil/event/domain/FlowEvent.java index c8704925..844cee61 100644 --- a/dil/src/main/java/org/assimbly/dil/event/FlowEvent.java +++ b/dil/src/main/java/org/assimbly/dil/event/domain/FlowEvent.java @@ -1,4 +1,4 @@ -package org.assimbly.dil.event; +package org.assimbly.dil.event.domain; import java.util.Date; diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/LogEvent.java b/dil/src/main/java/org/assimbly/dil/event/domain/LogEvent.java new file mode 100644 index 00000000..e5556ea9 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/LogEvent.java @@ -0,0 +1,97 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.io.IOException; + +/* +Note sometimes different names are used to be in sync with Karaf indices in Elastic + +This must be changed later after Camel2 isn't used). Change the JSONProperties to +their Java name to make them the same to DIL/Camel3. + */ + +public class LogEvent { + + private static final ObjectMapper mapper = new ObjectMapper(); + private String logLevel; + private String timestamp; + private String flowId; + private String tag; + private String message; + private String exception; + + public LogEvent(String timestamp, String flowId, String logLevel, String tag, String message, String exception) { + this.timestamp = timestamp; + this.flowId = flowId; + this.logLevel = logLevel; + this.tag = tag; + this.message = message; + this.exception = exception; + } + + @JsonProperty("logLevel") + public String getLogLevel() { + return this.logLevel; + } + + public void setLogLevel(String logLevel) { + this.logLevel = logLevel; + } + + @JsonProperty("timestamp") + public String getTimestamp() { + return this.timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + @JsonProperty("bundleId") + public String getFlowId() { + return this.flowId; + } + + public void setFlowId(String flowId) { + this.flowId = flowId; + } + + @JsonProperty("tag") + public String getTag() { + return this.tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + @JsonProperty("message") + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + @JsonProperty("exception") + public String getException() { + return this.exception; + } + + public void setException(String exception) { + this.exception = exception; + } + + public String toJson() { + mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + + try { + return mapper.writeValueAsString(this); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/MessageEvent.java b/dil/src/main/java/org/assimbly/dil/event/domain/MessageEvent.java new file mode 100644 index 00000000..7ee8b704 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/MessageEvent.java @@ -0,0 +1,117 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.quartz.impl.StdScheduler; + +import java.io.IOException; +import java.util.AbstractMap; +import java.util.Date; +import java.util.Map; +import java.util.stream.Collectors; + +/* +Note: + +1. Sometimes different names are used in the JSONProperties to be in sync with indices in Elastic +2. This must be changed later after Camel2 isn't used anymore. Change the JSONProperties to +their Java name to make them the same to DIL/Camel3. + */ + +public class MessageEvent { + private static final ObjectMapper mapper = new ObjectMapper(); + private static final String JMS_PREFIX = "JMS"; + + private final String id; + private final String stepId; + private final String flowVersion; + + private final String step; + private final String timestamp; + private final String expiryDate; + private final Map headers; + private final String body; + + public MessageEvent(String timestamp, String id, String stepId, String flowVersion, String step, Map headers, String body, String expiryDate) { + this.timestamp = timestamp; + this.id = id; + this.stepId = stepId; + this.flowVersion = flowVersion; + this.step = step; + this.headers = headers; + this.body = body; + this.expiryDate = expiryDate; + } + + @JsonProperty("timestamp") + public String getTimestamp() { + return timestamp; + } + + @JsonProperty("transactionId") + public String getId() { + return id; + } + + @JsonProperty("bundleId") + public String getStepId() { + return stepId; + } + + @JsonProperty("flowVersion") + public String getFlowVersion() { + return flowVersion; + } + + @JsonProperty("component") + public String getStep() { + return step; + } + + /** + * We strip away StdScheduler object because it contains circular references back to the Camel Context. + * which causes trouble for the serialization to JSON. + **/ + @JsonProperty("headers") + public Map getHeaders() { + return headers.entrySet() + .stream() + .filter(header -> !header.getKey().startsWith(JMS_PREFIX)) + .filter(header -> header.getValue() != null) + .filter(header -> !(header.getValue() instanceof StdScheduler)) + .filter(header -> !(header.getValue() instanceof Response)) + .filter(header -> !(header.getValue() instanceof Request)) + .map(entry -> { + if(entry.getKey().toLowerCase().contains("firetime") + && entry.getValue() instanceof Date) { + return new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().toString()); + } + + return entry; + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + @JsonProperty("body") + public String getBody() { + return body; + } + + @JsonProperty("expiry") + public String getExpiryDate() { + return expiryDate; + } + + public String toJson() { + mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + + try { + return mapper.writeValueAsString(this); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/StepEvent.java b/dil/src/main/java/org/assimbly/dil/event/domain/StepEvent.java new file mode 100644 index 00000000..9697ae54 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/StepEvent.java @@ -0,0 +1,99 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import java.io.IOException; + +/* +Note sometimes different names are used to be in sync with Karaf indices in Elastic + +This must be changed later after Camel2 isn't used). Change the JSONProperties to +their Java name to make them the same to DIL/Camel3. + */ + +public class StepEvent { + + private static final ObjectMapper mapper = new ObjectMapper(); + private String logLevel; + private String timestamp; + private String stepId; + private String tag; + private String message; + private String exception; + + public StepEvent(String timestamp, String stepId, String logLevel, String tag, String message, String exception) { + this.timestamp = timestamp; + this.stepId = stepId; + this.logLevel = logLevel; + this.tag = tag; + this.message = message; + this.exception = exception; + } + + @JsonProperty("logLevel") + public String getLogLevel() { + return this.logLevel; + } + + public void setLogLevel(String logLevel) { + this.logLevel = logLevel; + } + + @JsonProperty("timestamp") + public String getTimestamp() { + return this.timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + @JsonProperty("stepId") + public String getStepId() { + return this.stepId; + } + + public void setStepId(String stepId) { + this.stepId = stepId; + } + + @JsonProperty("tag") + public String getTag() { + return this.tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + @JsonProperty("message") + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + @JsonProperty("exception") + public String getException() { + return this.exception; + } + + public void setException(String exception) { + this.exception = exception; + } + + public String toJson() { + + mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + + try { + return mapper.writeValueAsString(this); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/event/domain/Store.java b/dil/src/main/java/org/assimbly/dil/event/domain/Store.java new file mode 100644 index 00000000..f3504dc7 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/domain/Store.java @@ -0,0 +1,48 @@ +package org.assimbly.dil.event.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Store{ + private String id; + private String type; + private String uri; + + private String expiryInHours; + + @JsonProperty("id") + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + @JsonProperty("type") + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + @JsonProperty("uri") + public String getUri() { + return this.uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + @JsonProperty("expiryInHours") + public String getExpiryInHours() { + return this.expiryInHours; + } + + public void setExpiryInHours(String expiryInHours) { + this.expiryInHours = expiryInHours; + } + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/store/StoreManager.java b/dil/src/main/java/org/assimbly/dil/event/store/StoreManager.java new file mode 100644 index 00000000..8ea70861 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/store/StoreManager.java @@ -0,0 +1,68 @@ +package org.assimbly.dil.event.store; + +import org.assimbly.dil.event.domain.Store; +import org.assimbly.dil.event.store.impl.ConsoleStore; +import org.assimbly.dil.event.store.impl.ElasticStore; +import org.assimbly.dil.event.store.impl.FileStore; + +import java.util.ArrayList; + +public class StoreManager { + + private FileStore fileStore; + private ElasticStore elasticStore; + private ConsoleStore consoleStore; + + private String collectorId; + + private ArrayList stores; + + + public StoreManager(String collectorId, ArrayList stores){ + this.collectorId = collectorId; + this.stores = stores; + storeSetup(); + } + + public void storeEvent(String json){ + + for(org.assimbly.dil.event.domain.Store store: stores){ + + switch (store.getType()) { + case "file": + fileStore.store(json); + break; + case "elastic": + elasticStore.store(json); + break; + case "console": + consoleStore.store(json); + break; + } + + } + + } + + private void storeSetup(){ + + for(org.assimbly.dil.event.domain.Store store: stores){ + + switch (store.getType()) { + case "file": + fileStore = new FileStore(collectorId, store); + break; + case "elastic": + elasticStore = new ElasticStore(collectorId, store); + break; + case "console": + consoleStore = new ConsoleStore(collectorId, store); + break; + } + + } + + } + + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/store/impl/ConsoleStore.java b/dil/src/main/java/org/assimbly/dil/event/store/impl/ConsoleStore.java new file mode 100644 index 00000000..aa07c629 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/store/impl/ConsoleStore.java @@ -0,0 +1,10 @@ +package org.assimbly.dil.event.store.impl; + +public class ConsoleStore { + public ConsoleStore(String collectorId, org.assimbly.dil.event.domain.Store store) { + } + + public void store(String json){ + System.out.println(json); + } +} diff --git a/dil/src/main/java/org/assimbly/dil/event/store/impl/ElasticStore.java b/dil/src/main/java/org/assimbly/dil/event/store/impl/ElasticStore.java new file mode 100644 index 00000000..8ab39301 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/store/impl/ElasticStore.java @@ -0,0 +1,86 @@ +package org.assimbly.dil.event.store.impl; + +import org.apache.http.HttpHost; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.ResponseListener; +import org.elasticsearch.client.RestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +public class ElasticStore { + + protected Logger log = LoggerFactory.getLogger(getClass()); + + RestClient restClient; + private final org.assimbly.dil.event.domain.Store store; + private String path; + + public ElasticStore(String collectorId, org.assimbly.dil.event.domain.Store store) { + + this.store = store; + + if(restClient == null){ + try { + start(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + } + + public void store(String json) { + + Request request = new Request("POST", path); + request.setJsonEntity(json); + + restClient.performRequestAsync(request, + new ResponseListener() { + @Override + public void onSuccess(Response response) { + log.debug("Insert into elasticsearch. json=" + json); + } + + @Override + public void onFailure(Exception exception) { + log.error("Failed to store event into elasticsearch. Reason: " + exception.getMessage()); + } + }); + } + + + + public void start() throws MalformedURLException { + + String uri = store.getUri(); + URL url = new URL(uri); + String protocol = url.getProtocol(); + String host = url.getHost(); + int port = url.getPort(); + path = url.getPath(); + + log.info("Start elasticsearch client for url: " + uri); + + restClient = RestClient.builder(new HttpHost(host, port, protocol)).build(); + } + + public void stop() throws IOException { + + String uri = store.getUri(); + + log.info("Stop elasticsearch client for url: " + uri); + + restClient.close(); + } + + public boolean isRunning() throws IOException { + return restClient.isRunning(); + } + + +} diff --git a/dil/src/main/java/org/assimbly/dil/event/store/impl/FileStore.java b/dil/src/main/java/org/assimbly/dil/event/store/impl/FileStore.java new file mode 100644 index 00000000..6917e437 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/store/impl/FileStore.java @@ -0,0 +1,55 @@ +package org.assimbly.dil.event.store.impl; + +import org.apache.commons.io.FileUtils; +import org.assimbly.util.BaseDirectory; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class FileStore { + + private final String baseDir = BaseDirectory.getInstance().getBaseDirectory(); + private File file; + private Date date = new Date(); + private String collectorId; + private org.assimbly.dil.event.domain.Store store; + + public FileStore(String collectorId, org.assimbly.dil.event.domain.Store store) { + this.collectorId = collectorId; + this.store = store; + + if(file==null){ + createFile(collectorId, store); + } + + } + + public void store(String json) { + List line = Arrays.asList(json); + try { + FileUtils.writeLines(file, line, true); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void createFile(String collectorid, org.assimbly.dil.event.domain.Store store){ + + String uri = store.getUri(); + String today = new SimpleDateFormat("yyyyMMdd").format(date); + + if(uri!=null) + file = new File(uri); + else{ + file = new File(baseDir + "/events/" + collectorid + "/" + today + "_events.log"); + } + + } + +} + + diff --git a/dil/src/main/java/org/assimbly/dil/event/util/EventUtil.java b/dil/src/main/java/org/assimbly/dil/event/util/EventUtil.java new file mode 100644 index 00000000..a9b328b1 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/event/util/EventUtil.java @@ -0,0 +1,26 @@ +package org.assimbly.dil.event.util; + +import org.assimbly.dil.event.domain.Filter; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +public class EventUtil { + + public static boolean isFiltered(final List filters, final String text){ + return filters.stream().filter(o -> text.matches(o.getFilter())).findFirst().isPresent(); + } + + public static String getTimestamp(){ + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + ZonedDateTime now = ZonedDateTime.now(Clock.systemUTC()); + + return formatter.format(now); + + } + + +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/loader/FlowLoaderReport.java b/dil/src/main/java/org/assimbly/dil/loader/FlowLoaderReport.java index 66b36eb5..d8258a89 100644 --- a/dil/src/main/java/org/assimbly/dil/loader/FlowLoaderReport.java +++ b/dil/src/main/java/org/assimbly/dil/loader/FlowLoaderReport.java @@ -24,7 +24,7 @@ public class FlowLoaderReport { public void initReport(String flowId, String flowName, String event){ String eventCapitalized = StringUtils.capitalize(event); - log.info(eventCapitalized + " flow | id=" + flowId); + log.info(eventCapitalized + " flow | flowid=" + flowId); json = new JSONObject(); flow = new JSONObject(); @@ -107,7 +107,7 @@ public void logResult(String flowId, String flowName, String event){ }else if(loadedError > 1){ log.error(loadedError + " steps failed to load"); } - log.error("Event=" + event + " | name=" + flowName + " | id=" + flowId); + log.error("Event=" + event + " | name=" + flowName + " | flowid=" + flowId); } } diff --git a/dil/src/main/java/org/assimbly/dil/transpiler/ssl/SSLConfiguration.java b/dil/src/main/java/org/assimbly/dil/transpiler/ssl/SSLConfiguration.java index 45147f4b..5982a5f0 100644 --- a/dil/src/main/java/org/assimbly/dil/transpiler/ssl/SSLConfiguration.java +++ b/dil/src/main/java/org/assimbly/dil/transpiler/ssl/SSLConfiguration.java @@ -25,7 +25,14 @@ public class SSLConfiguration { protected Logger log = LoggerFactory.getLogger(getClass()); - public void setUseGlobalSslContextParameters(CamelContext context,String componentName) throws Exception { + public void setUseGlobalSslContextParameters(CamelContext context,String[] sslComponentNames) throws Exception { + for (String sslComponent : sslComponentNames) { + setUseGlobalSslContextParameter(context, sslComponent); + } + } + + + public void setUseGlobalSslContextParameter(CamelContext context,String componentName) throws Exception { ((SSLContextParametersAware) context.getComponent(componentName)).setUseGlobalSslContextParameters(true); } @@ -89,7 +96,9 @@ public void createKeystore(String keystorePath){ public KeyStoreParameters createKeystoreParameters(String keystorePath, String keystorePassword){ KeyStoreParameters keystoreParameters = new KeyStoreParameters(); - keystoreParameters.setResource(keystorePath); + //keystoreParameters.setResource(keystorePath); + //keystoreParameters.setResource("keystore.jks"); + keystoreParameters.setResource("file:" + keystorePath); keystoreParameters.setPassword(keystorePassword); return keystoreParameters; diff --git a/dil/src/main/java/org/assimbly/dil/validation/XsltValidator.java b/dil/src/main/java/org/assimbly/dil/validation/XsltValidator.java new file mode 100755 index 00000000..0111117f --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/validation/XsltValidator.java @@ -0,0 +1,80 @@ +package org.assimbly.dil.validation; + +import net.sf.saxon.lib.StandardURIResolver; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XsltCompiler; +import org.assimbly.dil.validation.saxon.SaxonConfiguration; +import org.assimbly.util.error.ValidationErrorMessage; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.stream.StreamSource; +import java.util.ArrayList; +import java.util.List; + +public class XsltValidator { + + private static final String BASE = ""; + + private final Processor saxonProcessor; + + public XsltValidator() { + this.saxonProcessor = new Processor(new SaxonConfiguration()); + } + + public List validate(String url, String xsltBody) { + XsltCompiler xsltCompiler = saxonProcessor.newXsltCompiler(); + ValidationErrorListener errorListener = new ValidationErrorListener(); + xsltCompiler.setErrorListener(errorListener); + + try { + Source source = getXsltSource(url, xsltBody); + xsltCompiler.compile(source); + } catch (TransformerException | SaxonApiException e) { + errorListener.registerException(e); + } + + return errorListener.errors; + } + + private Source getXsltSource(String url, String xsltBody) throws TransformerException { + if(url != null) { + URIResolver uriResolver = new StandardURIResolver(); + return uriResolver.resolve(url, BASE); + } else { + if(xsltBody == null) { + return new StreamSource(new java.io.StringReader("")); + } + + return new StreamSource(new java.io.StringReader(xsltBody)); + } + } + + private class ValidationErrorListener implements ErrorListener { + + protected final List errors = new ArrayList<>(); + + public void registerException(Exception exception) { + errors.add(new ValidationErrorMessage(exception.getMessage())); + } + + @Override + public void warning(TransformerException e) { + registerException(e); + } + + @Override + public void error(TransformerException e) { + registerException(e); + } + + @Override + public void fatalError(TransformerException e) { + registerException(e); + } + } + +} \ No newline at end of file diff --git a/dil/src/main/java/org/assimbly/dil/validation/saxon/SaxonConfiguration.java b/dil/src/main/java/org/assimbly/dil/validation/saxon/SaxonConfiguration.java new file mode 100755 index 00000000..4caf084d --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/validation/saxon/SaxonConfiguration.java @@ -0,0 +1,10 @@ +package org.assimbly.dil.validation.saxon; + +import net.sf.saxon.Configuration; + +public class SaxonConfiguration extends Configuration { + + public SaxonConfiguration() { + registerExtensionFunction(new UuidExtensionFunction()); + } +} diff --git a/dil/src/main/java/org/assimbly/dil/validation/saxon/UuidExtensionFunction.java b/dil/src/main/java/org/assimbly/dil/validation/saxon/UuidExtensionFunction.java new file mode 100755 index 00000000..62cfbe7e --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/validation/saxon/UuidExtensionFunction.java @@ -0,0 +1,42 @@ +package org.assimbly.dil.validation.saxon; + +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.lib.ExtensionFunctionDefinition; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.StringValue; + +import java.util.UUID; + +public class UuidExtensionFunction extends ExtensionFunctionDefinition { + + @Override + public StructuredQName getFunctionQName() { + return new StructuredQName("uuid", "http://flux.kabisa.nl/uuid-saxon-extension", "uuid"); + } + + @Override + public SequenceType[] getArgumentTypes() { + return new SequenceType[0]; + } + + @Override + public SequenceType getResultType(SequenceType[] sequenceTypes) { + return SequenceType.SINGLE_STRING; + } + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { + UUID uuid = UUID.randomUUID(); + + return StringValue.makeStringValue(uuid.toString()); + } + }; + } +} diff --git a/integration/src/main/java/org/assimbly/integration/Integration.java b/integration/src/main/java/org/assimbly/integration/Integration.java index 2f71fe1c..15ac2545 100644 --- a/integration/src/main/java/org/assimbly/integration/Integration.java +++ b/integration/src/main/java/org/assimbly/integration/Integration.java @@ -89,6 +89,24 @@ public interface Integration { */ public String getFlowConfiguration(String flowId, String mediaType) throws Exception; + /** + * Add collector configuration from a string for a specific format (XML,JSON,YAML). + * + * @param collectorId Id of the collector (String) + * @param mediaType (XML,JSON,YAML) + * @param configuration (the XML, JSON or YAML file) + * @throws Exception if configuration can't be set + */ + public String addCollectorConfiguration(String collectorId, String mediaType, String configuration) throws Exception; + + /** + * Sets the collector configuration from a string for a specific format (XML,JSON,YAML). + * + * @param collectorId Id of the collector (String) + * @throws Exception if configuration can't be set + */ + public String removeCollectorConfiguration(String collectorId) throws Exception; + /** * gets the integration configuration currently set (in use). * @@ -120,7 +138,7 @@ public interface Integration { * @param host (dnsname or ip of server) * @param port number (1 through 65535) * @param timeOut in seconds - * @return Message "Connection succesfully opened" or "Connection error" + * @return Message "Connection successfully opened" or "Connection error" */ public String testConnection(String host, int port, int timeOut); @@ -887,7 +905,7 @@ public interface Integration { /** * Validates a cron expression * - * @param cron the cron expression + * @param cronExpression the cron expression * @return result of validation */ public ValidationErrorMessage validateCron(String cronExpression); @@ -895,7 +913,7 @@ public interface Integration { /** * Validates a certificate * - * @param certificate + * @param httpsUrl * @return result of validation */ public HttpsCertificateValidator.ValidationResult validateCertificate(String httpsUrl); @@ -910,7 +928,7 @@ public interface Integration { /** * Validates an expression * - * @param expression the expression (for example simple, xpath, jsonpath or Groovy) + * @param expressions the expression (for example simple, xpath, jsonpath or Groovy) * @return result of validation */ public List validateExpressions(List expressions); @@ -918,7 +936,7 @@ public interface Integration { /** * Validates a ftp expression * - * @param ftp + * @param ftpSettings * @return result of validation */ public ValidationErrorMessage validateFtp(FtpSettings ftpSettings); @@ -934,9 +952,18 @@ public interface Integration { /** * Validates a script * - * @param script the script (for example Groovy) + * @param scriptRequest the script (for example Groovy) * @return result of validation */ public EvaluationResponse validateScript(EvaluationRequest scriptRequest); + /** + * Validates a xslt + * + * @param url location of the XSLT file + * @param xsltBody the body of the XSLT file + * @return result of validation + */ + public List validateXslt(String url, String xsltBody); + } \ No newline at end of file diff --git a/integration/src/main/java/org/assimbly/integration/impl/BaseIntegration.java b/integration/src/main/java/org/assimbly/integration/impl/BaseIntegration.java index b5d6d1be..33c23a5e 100644 --- a/integration/src/main/java/org/assimbly/integration/impl/BaseIntegration.java +++ b/integration/src/main/java/org/assimbly/integration/impl/BaseIntegration.java @@ -283,6 +283,10 @@ public String testConnection(String host, int port, int timeOut) { public abstract void setHistoryMetrics(boolean historyMetrics); + public abstract String addCollectorConfiguration(String collectorId, String mediaType, String configuration) throws Exception; + + public abstract String removeCollectorConfiguration(String collectorId) throws Exception; + public abstract void addEventNotifier(EventNotifier eventNotifier) throws Exception; public abstract String getStats(String mediaType) throws Exception; @@ -451,4 +455,6 @@ public String testConnection(String host, int port, int timeOut) { public abstract EvaluationResponse validateScript(EvaluationRequest scriptRequest); + public abstract List validateXslt(String url, String xsltBody); + } diff --git a/integration/src/main/java/org/assimbly/integration/impl/CamelIntegration.java b/integration/src/main/java/org/assimbly/integration/impl/CamelIntegration.java index 11fa59af..600c2eef 100644 --- a/integration/src/main/java/org/assimbly/integration/impl/CamelIntegration.java +++ b/integration/src/main/java/org/assimbly/integration/impl/CamelIntegration.java @@ -21,7 +21,7 @@ import org.apache.camel.language.xpath.XPathBuilder; import org.apache.camel.spi.*; import org.apache.camel.support.DefaultExchange; -import org.apache.camel.support.jsse.SSLContextParameters; +import org.apache.camel.support.jsse.*; import org.apache.camel.util.concurrent.ThreadPoolRejectedPolicy; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; @@ -30,7 +30,9 @@ import org.assimbly.dil.blocks.beans.CustomHttpBinding; import org.assimbly.dil.blocks.beans.UuidExtensionFunction; import org.assimbly.dil.blocks.processors.*; +import org.assimbly.dil.event.EventConfigurer; import org.assimbly.dil.loader.FlowLoaderReport; +import org.assimbly.dil.transpiler.ssl.SSLConfiguration; import org.assimbly.dil.validation.*; import org.assimbly.dil.validation.beans.FtpSettings; import org.assimbly.dil.validation.beans.Regex; @@ -40,8 +42,6 @@ import org.assimbly.integration.loader.ConnectorRoute; import org.assimbly.dil.loader.FlowLoader; import org.assimbly.dil.blocks.connections.Connection; -import org.assimbly.dil.transpiler.ssl.SSLConfiguration; -import org.assimbly.dil.event.EventCollector; import org.assimbly.util.*; import org.assimbly.util.error.ValidationErrorMessage; import org.assimbly.util.file.DirectoryWatcher; @@ -55,10 +55,15 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.w3c.dom.Document; - +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.management.JMX; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; import java.io.File; +import java.lang.management.ManagementFactory; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.file.Files; @@ -122,9 +127,6 @@ public final void init(boolean useDefaultSettings) throws Exception { setDefaultSettings(); } - //collect events - context.getManagementStrategy().addEventNotifier(new EventCollector()); - //set management tasks routeController = context.getRouteController(); managed = context.getExtension(ManagedCamelContext.class); @@ -283,6 +285,31 @@ public void setRoutesDirectory(boolean deployOnEvent) throws Exception{ }*/ + public String addCollectorConfiguration(String collectorId, String mediaType, String configuration) throws Exception{ + + if(mediaType.contains("xml")){ + configuration = DocConverter.convertXmlToJson(configuration); + }else if(mediaType.contains("yaml")){ + configuration = DocConverter.convertYamlToJson(configuration); + } + + EventConfigurer eventConfigurer = new EventConfigurer(collectorId, context); + + String result = eventConfigurer.add(configuration); + + return result; + + } + + public String removeCollectorConfiguration(String collectorId) throws Exception{ + + EventConfigurer eventConfigurer = new EventConfigurer(collectorId, context); + + String result = eventConfigurer.remove(collectorId); + + return result; + } + public void setDeployDirectory(boolean deployOnStart, boolean deployOnEvent) throws Exception { @@ -884,23 +911,23 @@ public String startFlow(String id) { } if (status.isStarted()) { - finishFlowActionReport(id, "start","Started flow successfully | id=" + id,"info"); + finishFlowActionReport(id, "start","Started flow successfully","info"); }else{ - finishFlowActionReport(id, "error","Failed starting flow | id=" + id,"error"); + finishFlowActionReport(id, "error","Failed starting flow","error"); } }else if(result.equals("started")) { - finishFlowActionReport(id, "start","Started flow successfully | id=" + id,"info"); + finishFlowActionReport(id, "start","Started flow successfully","info"); } }catch (Exception e) { if(context.isStarted()) { stopFlow(id); - finishFlowActionReport(id, "error","Start flow failed | id=" + id + " | error=" + e.getMessage(),"error"); - log.error("Start flow failed. | id=" + id,e); + finishFlowActionReport(id, "error","Start flow failed | error=" + e.getMessage(),"error"); + log.error("Start flow failed. | flowid=" + id,e); }else{ - finishFlowActionReport(id, "error","Start flow failed | id=" + id + " | error=Integration isn't running","error"); - log.error("Start flow failed. | id=" + id,e); + finishFlowActionReport(id, "error","Start flow failed | error=Integration isn't running","error"); + log.error("Start flow failed. | flowid=" + id,e); } } @@ -915,11 +942,11 @@ private ServiceStatus startStep(Route route){ status = routeController.getRouteStatus(routeId); if(status.isStarted()) { - log.info("Started step | id=" + routeId); + log.info("Started step | stepid=" + routeId); } else { try { - log.info("Starting step | id=" + routeId); + log.info("Starting step | stepid=" + routeId); routeController.startRoute(routeId); @@ -933,11 +960,11 @@ private ServiceStatus startStep(Route route){ } while (status.isStarting() || count < 3000); } catch (Exception e) { - log.error("Failed starting step | id=" + routeId); + log.error("Failed starting step | stepid=" + routeId); return status; } - log.info("Started step | id=" + routeId); + log.info("Started step | stepid=" + routeId); } @@ -957,7 +984,7 @@ public String restartFlow(String id) { } }catch (Exception e) { - log.error("Restart flow failed. | id=" + id,e); + log.error("Restart flow failed. | flowid=" + id,e); finishFlowActionReport(id, "error", e.getMessage(),"error"); } @@ -976,16 +1003,16 @@ public String stopFlow(String id) { for (Route route : routeList) { String routeId = route.getId(); - log.info("Stopping step | id=" + route.getId()); + log.info("Stopping step | flowid=" + route.getId()); routeController.stopRoute(routeId, stopTimeout, TimeUnit.SECONDS); context.removeRoute(routeId); } - finishFlowActionReport(id, "stop","Stopped flow successfully | id=" + id,"info"); + finishFlowActionReport(id, "stop","Stopped flow successfully","info"); }catch (Exception e) { finishFlowActionReport(id, "error",e.getMessage(),"error"); - log.error("Stop flow failed. | id=" + id,e); + log.error("Stop flow failed. | flowid=" + id,e); } return loadReport; @@ -1020,10 +1047,10 @@ public String pauseFlow(String id) { do { status = routeController.getRouteStatus(routeId); if(status.isSuspended()) { - log.info("Paused (suspend) flow | id=" + id + "| step id=" + routeId); + log.info("Paused (suspend) flow | flowid=" + id + "| stepid=" + routeId); break; }else if(status.isStopped()){ - log.info("Paused (stopped) flow | id=" + id + "| step id=" + routeId); + log.info("Paused (stopped) flow | flowid=" + id + "| stepid=" + routeId); break; } @@ -1032,13 +1059,13 @@ public String pauseFlow(String id) { } while (status.isSuspending() || count < 6000); } - finishFlowActionReport(id, "pause","Paused flow successfully | id=" + id,"info"); + finishFlowActionReport(id, "pause","Paused flow successfully","info"); }else { String errorMessage = "Configuration is not set (use setConfiguration or setFlowConfiguration)"; finishFlowActionReport(id, "error",errorMessage,"error"); } }catch (Exception e) { - log.error("Pause flow failed. | id=" + id,e); + log.error("Pause flow failed. | flowid=" + id,e); stopFlow(id); //Stop flow if one of the routes cannot be paused. finishFlowActionReport(id, "error",e.getMessage(),"error"); } @@ -1073,7 +1100,7 @@ public String resumeFlow(String id) throws Exception { } while (status.isStarting() || count < 3000); resumed = true; - log.info("Resumed flow | id=" + id + " | step id=" + routeId); + log.info("Resumed flow | flowid=" + id + " | stepid=" + routeId); } else if (status.isStopped()){ @@ -1084,7 +1111,7 @@ else if (status.isStopped()){ } } if(resumed){ - finishFlowActionReport(id, "resume","Resumed flow successfully | id=" + id,"info"); + finishFlowActionReport(id, "resume","Resumed flow successfully","info"); }else { finishFlowActionReport(id, "error","Flow isn't suspended (nothing to resume)","error"); } @@ -1113,11 +1140,11 @@ private void finishFlowActionReport(String id, String event, String message, Str //logs event to if(messageType.equalsIgnoreCase("error")){ - log.error(eventCapitalized + " flow " + id + " failed.",message); + log.error(eventCapitalized + " flow " + id + " failed | flowid=" + id,message); }else if(messageType.equalsIgnoreCase("warning")) - log.warn(eventCapitalized + " flow " + id + " failed.",message); + log.warn(eventCapitalized + " flow" + id + " failed | flowid=" + id,message); else{ - log.info(message); + log.info(message + " | flowid=" + id); } TreeMap flowProps = null; @@ -1178,7 +1205,7 @@ public String getFlowInfo(String id, String mediaType) throws Exception { flow.put("status",getFlowStatus(id)); flow.put("uptime",getFlowUptime(id)); }else{ - flow.put("id",props.get("id")); + flow.put("id",id); flow.put("status",getFlowStatus(id)); } @@ -1626,14 +1653,13 @@ public String getFlowStats(String flowId, boolean fullStats, boolean includeStep flow.put("failed",failedMessages); flow.put("pending",pendingMessages); if(fullStats){ + flow.put("timeout",getTimeout(context)); flow.put("uptime",uptime); flow.put("uptimeMillis",uptimeMillis); flow.put("status",status); flow.put("tracing",tracing); flow.put("lastFailed",lastFailed); flow.put("lastCompleted",lastCompleted); - flow.put("failed",failedMessages); - flow.put("pending",pendingMessages); } if(includeSteps){ flow.put("steps",steps); @@ -1649,6 +1675,14 @@ public String getFlowStats(String flowId, boolean fullStats, boolean includeStep } + private long getTimeout(CamelContext context) throws MalformedObjectNameException { + String managementName = context.getManagementNameStrategy().getName(); + ObjectName objectName = context.getManagementStrategy().getManagementObjectNameStrategy().getObjectNameForCamelContext(managementName, context.getName()); + + ManagedCamelContextMBean managedCamelContextMBean = JMX.newMBeanProxy(ManagementFactory.getPlatformMBeanServer(), objectName, ManagedCamelContextMBean.class); + return managedCamelContextMBean.getTimeout(); + } + /* public String getFlowStats(String id, boolean fullStats, String mediaType) throws Exception { @@ -2393,6 +2427,12 @@ public EvaluationResponse validateScript(EvaluationRequest scriptRequest) { return scriptValidator.validate(scriptRequest); } + @Override + public List validateXslt(String url, String xsltBody) { + XsltValidator xsltValidator = new XsltValidator(); + return xsltValidator.validate(url, xsltBody); + } + public void setEncryptionProperties(Properties encryptionProperties) { this.encryptionProperties = encryptionProperties; setEncryptedPropertiesComponent(); @@ -2436,15 +2476,20 @@ private void setSSLContext() throws Exception { registry.bind("keystore", sslContextParametersKeystoreOnly); registry.bind("truststore", sslContextParametersTruststoreOnly); - context.setSSLContextParameters(sslContextParameters); + try { + SSLContext sslContext = sslContextParameters.createSSLContext(context); + SSLEngine engine = sslContext.createSSLEngine(); + }catch (Exception e){ + log.error("Can't set SSL context for certificate keystore. TLS/SSL certificates are not available. Reason: " + e.getMessage()); + } String[] sslComponents = {"ftps", "https", "imaps", "kafka", "jetty", "netty", "netty-http", "smtps", "vertx-http"}; - for (String sslComponent : sslComponents) { - sslConfiguration.setUseGlobalSslContextParameters(context, sslComponent); - } + sslConfiguration.setUseGlobalSslContextParameters(context, sslComponents); sslConfiguration.initTrustStoresForHttpsCertificateValidator(keyStorePath, "supersecret", trustStorePath, "supersecret"); + + } /** diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/FlowConfigurerRuntime.java b/integrationRest/src/main/java/org/assimbly/integrationrest/FlowConfigurerRuntime.java index f741c7a4..8761ac91 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/FlowConfigurerRuntime.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/FlowConfigurerRuntime.java @@ -32,11 +32,11 @@ public class FlowConfigurerRuntime { private Integration integration; /** - * POST /integration/{integrationId}/flow/{flowId}/configure : Set configuration from XML. + * POST /integration/{integrationId}/flow/{flowId}/configure : Set configuration. * * @param integrationId (integrationId) * @param flowId (FlowId) - * @param configuration as XML + * @param configuration as JSON or XML * @return the ResponseEntity with status 200 (Successful) and status 400 (Bad Request) if the configuration failed * @throws URISyntaxException if the Location URI syntax is incorrect */ diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/FlowManagerRuntime.java b/integrationRest/src/main/java/org/assimbly/integrationrest/FlowManagerRuntime.java index 034b61f0..aaf153cb 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/FlowManagerRuntime.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/FlowManagerRuntime.java @@ -61,8 +61,8 @@ public ResponseEntity startFlow(@Parameter(hidden = true) @RequestHeader status = DocConverter.convertJsonToXml(status); } - if (status.contains("Started flow successfully")) { - log.error("Start flow " + flowId + " successfully. Status:\n\n " + status); + if (status.contains("successfully")) { + log.info("Start flow " + flowId + " successfully. Status:\n\n " + status); return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/flow/{flowId}/start",status,plainResponse); } else { log.error("Start flow " + flowId + " failed. Status:\n\n" + status); @@ -279,7 +279,7 @@ public ResponseEntity uninstallFlow(@Parameter(hidden = true) @RequestHe } if (status.contains("Stopped flow successfully")) { - log.error("Uninstall flow " + flowId + " succesfully. Status: " + status); + log.error("Uninstall flow " + flowId + " successfully. Status: " + status); return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/flow/{flowId}/uninstall",status,plainResponse); } else { log.error("Uninstall flow " + flowId + " failed. Status: " + status); diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/IntegrationRuntime.java b/integrationRest/src/main/java/org/assimbly/integrationrest/IntegrationRuntime.java index 8d7880d0..17d2e4cf 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/IntegrationRuntime.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/IntegrationRuntime.java @@ -3,7 +3,7 @@ import io.swagger.v3.oas.annotations.Parameter; import org.assimbly.integration.Integration; import org.assimbly.integration.impl.CamelIntegration; -import org.assimbly.integrationrest.event.FailureListener; +import org.assimbly.integrationrest.event.FailureCollector; import org.assimbly.util.rest.ResponseUtil; import org.slf4j.Logger; @@ -37,7 +37,7 @@ public class IntegrationRuntime { private boolean integrationIsStarting; @Autowired - private FailureListener failureListener; + private FailureCollector failureCollector; public IntegrationRuntime() throws Exception { } @@ -63,7 +63,7 @@ public ResponseEntity start(@Parameter(hidden = true) @RequestHeader("Ac if (integration.isStarted()) { return ResponseUtil.createFailureResponse(integrationId, mediaType, "/integration/{integrationId}/start", "Integration already running"); } else { - integration.addEventNotifier(failureListener); + integration.addEventNotifier(failureCollector); integration.setTracing(false, "default"); integration.start(); return ResponseUtil.createSuccessResponse(integrationId, mediaType, "/integration/{integrationId}/start", "Integration started"); @@ -278,6 +278,57 @@ public ResponseEntity getIntegrationNumberOfAlerts(@Parameter(hidden = t } } + /** + * POST /integration/{integrationId}/collector/{collectorId}/add : Set collector configuration + * + * @param integrationId (integrationId) + * @param collectorId (CollectorId) + * @param configuration as JSON or XML + * @return the ResponseEntity with status 200 (Successful) and status 400 (Bad Request) if setting of the configuration failed + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping(path = "/integration/{integrationId}/collector/{collectorId}/add", consumes = {"application/json", "application/xml", "text/plain"}, produces = {"application/json","application/xml","text/plain"}) + public ResponseEntity addCollectorConfiguration(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType, @PathVariable Long integrationId, @PathVariable String collectorId, @RequestBody String configuration) throws Exception { + + log.info("Add collector with id=" + collectorId); + + try { + String result = integration.addCollectorConfiguration(collectorId,mediaType, configuration); + if(!result.equalsIgnoreCase("configured")){ + log.error("Add collector " + collectorId + " failed. Message: " + result); + return ResponseUtil.createFailureResponse(integrationId, mediaType,"/integration/{integrationId}/collector/{collectorId}/add",result); + } + + return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/collector/{collectorId}/add",result); + } catch (Exception e) { + log.error("Add collector " + collectorId + " failed",e); + return ResponseUtil.createFailureResponse(integrationId, mediaType,"/integration/{integrationId}/collector/{collectorId}/add",e.getMessage()); + } + + } + + /** + * DELETE /integration/{integrationId}/collector/{collectorId}/remove : Remove collector configuration + * + * @param integrationId (integrationId) + * @param collectorId (CollectorId) + * @return the ResponseEntity with status 200 (Successful) and status 400 (Bad Request) if the remove of configuration failed + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @DeleteMapping(path = "/integration/{integrationId}/collector/{collectorId}/remove", produces = {"application/json","application/xml","text/plain"}) + public ResponseEntity removeCollectorConfiguration(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType, @PathVariable Long integrationId, @PathVariable String collectorId) throws Exception { + + log.info("Remove collector with id=" + collectorId); + + try { + String result = integration.removeCollectorConfiguration(collectorId); + return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/collector/{collectorId}/remove",result); + } catch (Exception e) { + log.error("Remove collector " + collectorId + " failed",e); + return ResponseUtil.createFailureResponse(integrationId, mediaType,"/integration/{integrationId}/collector/{collectorId}/remove",e.getMessage()); + } + + } // Generates a generic error response (exceptions outside try catch): @ExceptionHandler({Exception.class}) @@ -305,7 +356,7 @@ public void initIntegration(){ try { //add notifier before starting integration - integration.addEventNotifier(failureListener); + integration.addEventNotifier(failureCollector); integration.start(); integrationIsStarting = true; diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/MessageManagerRuntime.java b/integrationRest/src/main/java/org/assimbly/integrationrest/MessageManagerRuntime.java index 3c602295..74753aeb 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/MessageManagerRuntime.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/MessageManagerRuntime.java @@ -77,7 +77,7 @@ public ResponseEntity send(@Parameter(hidden = true) @RequestHeader("Acc integration.sendWithHeaders(uri, body, headerMap, numberOfTimes); } - return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/send","Sent succesfully"); + return ResponseUtil.createSuccessResponse(integrationId, mediaType,"/integration/{integrationId}/send","Sent successfully"); } catch (Exception e) { log.error("Send message to " + uri + " failed",e); return ResponseUtil.createFailureResponse(integrationId, mediaType,"/integration/{integrationId}/send","Error: " + e.getMessage() + " Cause: " + e.getCause()); diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/ValidationRuntime.java b/integrationRest/src/main/java/org/assimbly/integrationrest/ValidationRuntime.java index 31f6f9fa..7e998ebe 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/ValidationRuntime.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/ValidationRuntime.java @@ -13,10 +13,10 @@ import org.assimbly.integration.Integration; import org.assimbly.util.error.ValidationErrorMessage; import org.assimbly.util.rest.ResponseUtil; -import org.eclipse.jetty.util.security.CertificateValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -294,6 +294,47 @@ public ResponseEntity validateUri(@Parameter(hidden = true) @RequestHead } } + @PostMapping(path = "/validation/{integrationId}/xslt", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE} + ) + public ResponseEntity validateXslt( + @Parameter(hidden = true) @RequestHeader("Accept") String mediaType, + @RequestHeader(value = "StopTest", defaultValue = "false") boolean stopTest, + @PathVariable Long integrationId, + @RequestBody String body + ) throws Exception { + + plainResponse = true; + + try { + HashMap paramList = null; + if(body!=null){ + paramList = new ObjectMapper().readValue(body, new TypeReference>(){}); + } + + integration = integrationRuntime.getIntegration(); + List expressionResp = integration.validateXslt( + paramList.get("xsltUrl"), + paramList.get("xsltBody") + ); + + if(expressionResp!=null) { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(out, expressionResp); + return ResponseUtil.createSuccessResponse(integrationId, mediaType, "/validation/{integrationId}/xslt", out.toString(), plainResponse); + } else { + return ResponseUtil.createNoContentResponse(integrationId, mediaType); + } + + } catch (Exception e) { + log.error("Error",e); + return ResponseUtil.createFailureResponse(integrationId, mediaType, "/validation/{integrationId}/xslt", e.getMessage(), plainResponse); + } + + } + @GetMapping(path = "/validation/{integrationId}/connection/{host}/{port}/{timeout}", produces = {"text/plain","application/xml","application/json"}) public ResponseEntity testConnection(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType, @PathVariable Long integrationId, @PathVariable String host,@PathVariable int port, @PathVariable int timeout) throws Exception { diff --git a/integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureListener.java b/integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureCollector.java similarity index 95% rename from integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureListener.java rename to integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureCollector.java index 2d65c84a..25d727bb 100644 --- a/integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureListener.java +++ b/integrationRest/src/main/java/org/assimbly/integrationrest/event/FailureCollector.java @@ -14,7 +14,7 @@ // Check the following page for all EventObject instances of Camel: http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/management/event/package-summary.html @Component -public class FailureListener extends EventNotifierSupport { +public class FailureCollector extends EventNotifierSupport { protected Logger log = LoggerFactory.getLogger(getClass()); @@ -54,7 +54,7 @@ public void notify(CamelEvent event) throws Exception { if (flowIdPart != -1) { - flowId= flowId.substring(0 , flowIdPart); //this will give abc + flowId= flowId.substring(0 , flowIdPart); } if(this.messagingTemplate!=null) { diff --git a/pom.xml b/pom.xml index 789f5b1a..73760322 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 11 UTF-8 ${project.basedir} - 3.8.2 + 3.9.0