com.jayway.jsonpath
json-path
diff --git a/core/src/main/java/com/predic8/membrane/core/Router.java b/core/src/main/java/com/predic8/membrane/core/Router.java
index a49d8105b6..4bc75769ee 100644
--- a/core/src/main/java/com/predic8/membrane/core/Router.java
+++ b/core/src/main/java/com/predic8/membrane/core/Router.java
@@ -14,39 +14,64 @@
package com.predic8.membrane.core;
-import com.predic8.membrane.annot.*;
-import com.predic8.membrane.core.RuleManager.*;
-import com.predic8.membrane.core.config.spring.*;
-import com.predic8.membrane.core.exchangestore.*;
-import com.predic8.membrane.core.interceptor.*;
-import com.predic8.membrane.core.interceptor.administration.*;
-import com.predic8.membrane.core.jmx.*;
-import com.predic8.membrane.core.kubernetes.*;
-import com.predic8.membrane.core.kubernetes.client.*;
-import com.predic8.membrane.core.openapi.*;
-import com.predic8.membrane.core.openapi.serviceproxy.*;
-import com.predic8.membrane.core.proxies.*;
-import com.predic8.membrane.core.resolver.*;
-import com.predic8.membrane.core.transport.*;
-import com.predic8.membrane.core.transport.http.*;
-import com.predic8.membrane.core.transport.http.client.*;
-import com.predic8.membrane.core.util.*;
-import org.slf4j.*;
-import org.springframework.beans.*;
-import org.springframework.beans.factory.*;
-import org.springframework.context.*;
-import org.springframework.context.support.*;
-
-import javax.annotation.concurrent.*;
-import java.io.*;
-import java.util.Timer;
+import com.predic8.membrane.annot.MCAttribute;
+import com.predic8.membrane.annot.MCChildElement;
+import com.predic8.membrane.annot.MCElement;
+import com.predic8.membrane.annot.MCMain;
+import com.predic8.membrane.annot.yaml.BeanCacheObserver;
+import com.predic8.membrane.annot.yaml.BeanDefinition;
+import com.predic8.membrane.annot.yaml.WatchAction;
+import com.predic8.membrane.core.RuleManager.RuleDefinitionSource;
+import com.predic8.membrane.core.config.spring.BaseLocationApplicationContext;
+import com.predic8.membrane.core.config.spring.GrammarAutoGenerated;
+import com.predic8.membrane.core.config.spring.TrackingApplicationContext;
+import com.predic8.membrane.core.config.spring.TrackingFileSystemXmlApplicationContext;
+import com.predic8.membrane.core.exceptions.SpringConfigurationErrorHandler;
+import com.predic8.membrane.core.exchangestore.ExchangeStore;
+import com.predic8.membrane.core.exchangestore.LimitedMemoryExchangeStore;
+import com.predic8.membrane.core.interceptor.ExchangeStoreInterceptor;
+import com.predic8.membrane.core.interceptor.FlowController;
+import com.predic8.membrane.core.interceptor.GlobalInterceptor;
+import com.predic8.membrane.core.interceptor.administration.AdminConsoleInterceptor;
+import com.predic8.membrane.core.jmx.JmxExporter;
+import com.predic8.membrane.core.jmx.JmxRouter;
+import com.predic8.membrane.core.kubernetes.KubernetesWatcher;
+import com.predic8.membrane.core.kubernetes.client.KubernetesClientFactory;
+import com.predic8.membrane.core.openapi.OpenAPIParsingException;
+import com.predic8.membrane.core.openapi.serviceproxy.DuplicatePathException;
+import com.predic8.membrane.core.proxies.ApiInfo;
+import com.predic8.membrane.core.proxies.Proxy;
+import com.predic8.membrane.core.proxies.SSLableProxy;
+import com.predic8.membrane.core.resolver.ResolverMap;
+import com.predic8.membrane.core.transport.Transport;
+import com.predic8.membrane.core.transport.http.HttpClientFactory;
+import com.predic8.membrane.core.transport.http.HttpServerThreadFactory;
+import com.predic8.membrane.core.transport.http.HttpTransport;
+import com.predic8.membrane.core.transport.http.client.HttpClientConfiguration;
+import com.predic8.membrane.core.util.ConfigurationException;
+import com.predic8.membrane.core.util.DNSCache;
+import com.predic8.membrane.core.util.TimerManager;
+import com.predic8.membrane.core.util.URIFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.Lifecycle;
+import org.springframework.context.support.AbstractRefreshableApplicationContext;
+
+import javax.annotation.concurrent.GuardedBy;
+import java.io.IOException;
import java.util.*;
-import java.util.concurrent.*;
+import java.util.concurrent.ExecutorService;
-import static com.predic8.membrane.core.Constants.*;
-import static com.predic8.membrane.core.util.DLPUtil.*;
-import static com.predic8.membrane.core.jmx.JmxExporter.*;
-import static java.util.concurrent.Executors.*;
+import static com.predic8.membrane.core.Constants.PRODUCT_NAME;
+import static com.predic8.membrane.core.Constants.VERSION;
+import static com.predic8.membrane.core.jmx.JmxExporter.JMX_EXPORTER_NAME;
+import static com.predic8.membrane.core.util.DLPUtil.displayTraceWarning;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
/**
* @description
@@ -70,7 +95,7 @@
outputName = "router-conf.xsd",
targetNamespace = "http://membrane-soa.org/proxies/1/")
@MCElement(name = "router")
-public class Router implements Lifecycle, ApplicationContextAware, BeanNameAware {
+public class Router implements Lifecycle, ApplicationContextAware, BeanNameAware, BeanCacheObserver {
private static final Logger log = LoggerFactory.getLogger(Router.class.getName());
@@ -246,16 +271,6 @@ public ExecutorService getBackgroundInitializer() {
return backgroundInitializer;
}
- public Proxy getParentProxy(Interceptor interceptor) {
- for (Proxy r : getRuleManager().getRules()) {
- if (r.getFlow() != null)
- for (Interceptor i : r.getFlow())
- if (i == interceptor)
- return r;
- }
- throw new IllegalArgumentException("No parent proxy found for the given interceptor.");
- }
-
public void add(Proxy proxy) throws IOException {
if (!(proxy instanceof SSLableProxy sp)) {
ruleManager.addProxy(proxy, RuleDefinitionSource.MANUAL);
@@ -673,4 +688,38 @@ public void handleAsynchronousInitializationResult(boolean success) {
log.info("{} {} up and running!", PRODUCT_NAME, VERSION);
setAsynchronousInitialization(false);
}
+
+ @Override
+ public void handleBeanEvent(BeanDefinition bd, Object bean, Object oldBean) throws IOException {
+ if (!(bean instanceof Proxy)) {
+ throw new IllegalArgumentException("Bean must be a Proxy instance, but got: " + bean.getClass().getName());
+ }
+
+ Proxy newProxy = (Proxy) bean;
+ if (newProxy.getName() == null)
+ newProxy.setName(bd.getName());
+
+ try {
+ newProxy.init(this);
+ }
+ catch (ConfigurationException e) {
+ SpringConfigurationErrorHandler.handleRootCause(e, log);
+ throw e;
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Could not init rule.", e);
+ }
+
+ if (bd.getAction() == WatchAction.ADDED)
+ add(newProxy);
+ else if (bd.getAction() == WatchAction.DELETED)
+ getRuleManager().removeRule((Proxy) oldBean);
+ else if (bd.getAction() == WatchAction.MODIFIED)
+ getRuleManager().replaceRule((Proxy) oldBean, newProxy);
+ }
+
+ @Override
+ public boolean isActivatable(BeanDefinition bd) {
+ return Proxy.class.isAssignableFrom(new GrammarAutoGenerated().getElement(bd.getKind()));
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java b/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java
index 5186953a9b..a85388aa79 100644
--- a/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java
+++ b/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java
@@ -14,13 +14,12 @@
package com.predic8.membrane.core.cli;
+import com.predic8.membrane.annot.yaml.*;
import com.predic8.membrane.core.*;
-import com.predic8.membrane.core.config.spring.TrackingFileSystemXmlApplicationContext;
+import com.predic8.membrane.core.config.spring.*;
import com.predic8.membrane.core.exceptions.*;
-import com.predic8.membrane.core.kubernetes.BeanCache;
import com.predic8.membrane.core.openapi.serviceproxy.*;
import com.predic8.membrane.core.resolver.*;
-import com.predic8.membrane.core.util.ConfigurationException;
import org.apache.commons.cli.*;
import org.jetbrains.annotations.*;
import org.slf4j.*;
@@ -29,19 +28,17 @@
import java.io.*;
import java.util.*;
+import static com.predic8.membrane.annot.yaml.GenericYamlParser.*;
import static com.predic8.membrane.core.Constants.*;
-import static com.predic8.membrane.core.cli.util.JwkGenerator.generateJWK;
-import static com.predic8.membrane.core.cli.util.JwkGenerator.privateJWKtoPublic;
-import static com.predic8.membrane.core.cli.util.YamlLoader.sendYamlToBeanCache;
+import static com.predic8.membrane.core.cli.util.JwkGenerator.*;
import static com.predic8.membrane.core.config.spring.TrackingFileSystemXmlApplicationContext.*;
import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.*;
-import static com.predic8.membrane.core.openapi.util.OpenAPIUtil.isOpenAPIMisplacedError;
+import static com.predic8.membrane.core.openapi.util.OpenAPIUtil.*;
import static com.predic8.membrane.core.util.ExceptionUtil.*;
import static com.predic8.membrane.core.util.OSUtil.*;
import static com.predic8.membrane.core.util.URIUtil.*;
import static java.lang.Integer.*;
-import static org.apache.commons.lang3.exception.ExceptionUtils.getMessage;
-import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage;
+import static org.apache.commons.lang3.exception.ExceptionUtils.*;
public class RouterCLI {
@@ -132,7 +129,7 @@ public static String getExceptionMessageWithCauses(Throwable throwable) {
private static Router initRouterByConfig(MembraneCommandLine commandLine) throws Exception {
String config = getRulesFile(commandLine);
- if(config.endsWith(".xml")) {
+ if (config.endsWith(".xml")) {
return initRouterByXml(config);
}
if (config.endsWith(".yaml") || config.endsWith(".yml")) {
@@ -149,8 +146,7 @@ private static Router initRouterByOpenApiSpec(MembraneCommandLine commandLine) t
}
private static Router initRouterByYAML(MembraneCommandLine commandLine, String option) throws Exception {
- String location = commandLine.getCommand().getOptionValue(option);
- return initRouterByYAML(location);
+ return initRouterByYAML(commandLine.getCommand().getOptionValue(option));
}
private static Router initRouterByYAML(String location) throws Exception {
@@ -160,9 +156,8 @@ private static Router initRouterByYAML(String location) throws Exception {
router.setAsynchronousInitialization(true);
router.start();
- var beanCache = new BeanCache(router);
- beanCache.start();
- sendYamlToBeanCache(router, location, beanCache);
+ new BeanRegistryImplementation(router, new GrammarAutoGenerated()).registerBeanDefinitions(parseMembraneResources(router.getResolverMap().resolve(location), new GrammarAutoGenerated()));
+
return router;
}
@@ -238,10 +233,10 @@ private static String getRulesFile(MembraneCommandLine cl) throws IOException {
}
return getRulesFileFromRelativeSpec(rm, filename, "");
}
- return getDefaultConfig(rm);
+ return getDefaultConfig();
}
- private static String getDefaultConfig(ResolverMap rm) {
+ private static String getDefaultConfig() {
String callerDir = System.getenv("MEMBRANE_CALLER_DIR");
if (callerDir == null || callerDir.isEmpty()) {
callerDir = getUserDir();
@@ -296,7 +291,7 @@ private static String getConfiguration(MembraneCommandLine cl) {
private static boolean hasConfiguration(MembraneCommandLine cl) {
return cl.getCommand().isOptionSet("c") ||
- cl.getCommand().isOptionSet("t");
+ cl.getCommand().isOptionSet("t");
}
private static String getErrorNotice() {
diff --git a/core/src/main/java/com/predic8/membrane/core/cli/util/YamlLoader.java b/core/src/main/java/com/predic8/membrane/core/cli/util/YamlLoader.java
deleted file mode 100644
index 76b67e86e5..0000000000
--- a/core/src/main/java/com/predic8/membrane/core/cli/util/YamlLoader.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Copyright 2025 predic8 GmbH, www.predic8.com
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
-
-package com.predic8.membrane.core.cli.util;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
-import com.networknt.schema.InputFormat;
-import com.predic8.membrane.core.Router;
-import com.predic8.membrane.core.interceptor.Interceptor;
-import com.predic8.membrane.core.interceptor.schemavalidation.json.JSONYAMLSchemaValidator;
-import com.predic8.membrane.core.kubernetes.BeanCache;
-import com.predic8.membrane.core.kubernetes.client.WatchAction;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.TreeMap;
-
-import static com.fasterxml.jackson.core.StreamReadFeature.STRICT_DUPLICATE_DETECTION;
-import static com.fasterxml.jackson.dataformat.yaml.YAMLFactory.builder;
-import static com.predic8.membrane.core.http.Request.post;
-import static com.predic8.membrane.core.interceptor.Outcome.ABORT;
-import static com.predic8.membrane.core.interceptor.schemavalidation.json.JSONYAMLSchemaValidator.SCHEMA_VERSION_2020_12;
-import static java.nio.file.Files.readString;
-import static java.util.UUID.randomUUID;
-
-public class YamlLoader {
- private static final Logger log = LoggerFactory.getLogger(YamlLoader.class);
-
- private static final ObjectMapper om = new ObjectMapper();
-
- public static void sendYamlToBeanCache(Router router, String location, BeanCache beanCache) throws Exception {
- validate(router, location);
-
- final YAMLFactory yamlFactory = builder().enable(STRICT_DUPLICATE_DETECTION).build();
-
- try (YAMLParser parser = yamlFactory.createParser(new File(location))) {
- int count = 0;
-
- while (!parser.isClosed()) {
- Map m = om.readValue(parser, Map.class);
- if (m == null) {
- log.debug("Skipping empty document. Maybe there are two --- separators but no configuration in between.");
- parser.nextToken();
- continue;
- }
-
- count++;
- fillMissingFields(location, m, count);
-
- beanCache.handle(WatchAction.ADDED, m);
- parser.nextToken();
- }
-
- beanCache.fireConfigurationLoaded();
- } catch (JsonParseException e) {
- throw new IOException(
- "Invalid YAML: multiple configurations must be separated by '---' "
- + "(at line " + e.getLocation().getLineNr()
- + ", column " + e.getLocation().getColumnNr() + ").",
- e
- );
- }
- }
-
- private static void fillMissingFields(String location, Map m, int count) {
- Map meta = (Map) m.get("metadata");
- if (meta == null) {
- // generate name, if it doesnt exist
- meta = new TreeMap<>();
- m.put("metadata", meta);
- meta.put("name", "artifact" + count);
- meta.put("uid", randomUUID().toString());
- } else {
- // fake UID
- meta.put("uid", location + "-" + meta.get("name"));
- }
- }
-
- private static void validate(Router router, String location) throws Exception {
- var configExchange = post("http://localhost/config")
- .body(readString(new File(location).toPath()))
- .buildExchange();
- var validator = new JSONYAMLSchemaValidator(
- router.getResolverMap(),
- "classpath:/com/predic8/membrane/core/config/json/membrane.schema.json",
- (message, exc) -> log.error(message),
- SCHEMA_VERSION_2020_12,
- InputFormat.YAML
- );
- validator.init();
- if (validator.validateMessage(configExchange, Interceptor.Flow.REQUEST) == ABORT)
- System.exit(1);
- }
-}
diff --git a/core/src/main/java/com/predic8/membrane/core/config/ProxyAware.java b/core/src/main/java/com/predic8/membrane/core/config/ProxyAware.java
new file mode 100644
index 0000000000..521e11743b
--- /dev/null
+++ b/core/src/main/java/com/predic8/membrane/core/config/ProxyAware.java
@@ -0,0 +1,23 @@
+/* Copyright 2025 predic8 GmbH, www.predic8.com
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. */
+
+package com.predic8.membrane.core.config;
+
+import com.predic8.membrane.core.proxies.Proxy;
+
+public interface ProxyAware {
+
+ void setProxy(Proxy proxy);
+
+}
diff --git a/core/src/main/java/com/predic8/membrane/core/config/spring/k8s/Envelope.java b/core/src/main/java/com/predic8/membrane/core/config/spring/k8s/Envelope.java
index 7812b4f4a4..d6e9a4879c 100644
--- a/core/src/main/java/com/predic8/membrane/core/config/spring/k8s/Envelope.java
+++ b/core/src/main/java/com/predic8/membrane/core/config/spring/k8s/Envelope.java
@@ -13,74 +13,28 @@
limitations under the License. */
package com.predic8.membrane.core.config.spring.k8s;
-import com.predic8.membrane.annot.K8sHelperGenerator;
-import com.predic8.membrane.core.config.spring.K8sHelperGeneratorAutoGenerated;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.predic8.membrane.annot.Grammar;
+import com.predic8.membrane.core.config.spring.GrammarAutoGenerated;
import com.predic8.membrane.annot.yaml.BeanRegistry;
-import com.predic8.membrane.annot.yaml.GenericYamlParser;
-import org.yaml.snakeyaml.events.Event;
-import org.yaml.snakeyaml.events.MappingEndEvent;
-import org.yaml.snakeyaml.events.MappingStartEvent;
-import org.yaml.snakeyaml.events.ScalarEvent;
import java.util.*;
-import static com.predic8.membrane.annot.yaml.YamlLoader.readObj;
-import static com.predic8.membrane.annot.yaml.YamlLoader.readString;
-
public class Envelope {
String kind;
String apiVersion;
Metadata metadata;
- Object spec;
+ JsonNode spec;
final Map additionalProperties = new HashMap<>();
- private static final K8sHelperGenerator K8S_HELPER = new K8sHelperGeneratorAutoGenerated();
+ private static final Grammar K8S_HELPER = new GrammarAutoGenerated();
- public void parse(Iterator events, BeanRegistry registry) {
- int state = 0;
- while (events.hasNext()) {
- Event event = events.next();
- switch (state) {
- case 0:
- if (event instanceof MappingStartEvent)
- state = 1;
- break;
- case 1:
- if (event instanceof ScalarEvent se) {
- String value = se.getValue();
- switch (value) {
- case "kind":
- kind = readString(events);
- break;
- case "apiVersion":
- apiVersion = readString(events);
- break;
- case "spec":
- spec = readSpec(kind, events, registry);
- break;
- case "metadata":
- metadata = readMetadata(events);
- break;
- default:
- additionalProperties.put(value, readObj(events));
- break;
- }
- } else if (event instanceof MappingEndEvent) {
- return;
- } else {
- throw new IllegalStateException("Expected scalar or end-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
- }
- }
- }
- }
-
- private Object readSpec(String kind, Iterator events, BeanRegistry registry) {
- if (kind == null)
- kind = "api";
- Class clazz = K8S_HELPER.getElement(kind);
- if (clazz == null)
- throw new RuntimeException("Did not find java class for kind '%s'.".formatted(kind));
- return GenericYamlParser.parse(kind, clazz, events, registry, K8S_HELPER);
+ public void parse(JsonNode node, BeanRegistry registry) {
+ kind = node.get("kind").asText();
+ apiVersion = node.get("apiVersion").asText();
+ metadata = readMetadata(node.get("metadata"));
+ spec = node.get("spec");
+ //GenericYamlParser.parse(kind, clazz, events, registry, K8S_HELPER);
}
public static class Metadata {
@@ -94,35 +48,11 @@ public String getUid() {
}
}
- private Metadata readMetadata(Iterator events) {
- Event event = events.next();
- if (!(event instanceof MappingStartEvent))
- throw new IllegalStateException("Expected map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
+ private Metadata readMetadata(JsonNode node) {
Metadata metadata = new Metadata();
- while (events.hasNext()) {
- event = events.next();
- if (event instanceof ScalarEvent se) {
- String value = se.getValue();
- switch (value) {
- case "name":
- metadata.name = readString(events);
- break;
- case "namespace":
- metadata.namespace = readString(events);
- break;
- case "uid":
- metadata.uid = readString(events);
- break;
- default:
- metadata.additionalProperties.put(value, readObj(events));
- break;
- }
- } else if (event instanceof MappingEndEvent) {
- break;
- } else {
- throw new IllegalStateException("Expected scalar or end-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
- }
- }
+ metadata.name = node.get("name").asText();
+ metadata.namespace = node.get("namespace").asText();
+ metadata.uid = node.get("uid").asText();
return metadata;
}
diff --git a/core/src/main/java/com/predic8/membrane/core/exceptions/SpringConfigurationErrorHandler.java b/core/src/main/java/com/predic8/membrane/core/exceptions/SpringConfigurationErrorHandler.java
index 5a355a460f..83a65a57a7 100644
--- a/core/src/main/java/com/predic8/membrane/core/exceptions/SpringConfigurationErrorHandler.java
+++ b/core/src/main/java/com/predic8/membrane/core/exceptions/SpringConfigurationErrorHandler.java
@@ -138,7 +138,7 @@ private static void handleConfigurationException(ConfigurationException ce) {
Giving up.
- Check proxies.xml file for errors.
+ Check apis.yaml or proxies.xml file for errors.
%n""", ce.getMessage(),reason);
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/AbstractInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/AbstractInterceptor.java
index 049de79d4c..0c898eab62 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/AbstractInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/AbstractInterceptor.java
@@ -105,25 +105,9 @@ public final void init(Router router) {
init();
}
- public T getProxy(){
- return (T)getRouter()
- .getRuleManager()
- .getRules()
- .stream()
- .filter(proxy -> proxy
- .getFlow() != null)
- .filter(proxy -> proxy
- .getFlow()
- .stream().anyMatch(this::hasSameReferenceAs))
- .findAny()
- .get();
- }
-
- private boolean hasSameReferenceAs(Interceptor i){
- if(i instanceof AbstractFlowWithChildrenInterceptor){
- return ((AbstractFlowWithChildrenInterceptor) i).getFlow().stream().anyMatch(this::hasSameReferenceAs);
- }
- return i == this;
+ @Override
+ public void init(Router router, Proxy ignored) {
+ init(router);
}
public Router getRouter() { //wird von ReadRulesConfigurationTest aufgerufen.
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/Interceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/Interceptor.java
index 6b6ff30e64..29486c68e6 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/Interceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/Interceptor.java
@@ -16,6 +16,7 @@
import com.predic8.membrane.core.*;
import com.predic8.membrane.core.exchange.*;
+import com.predic8.membrane.core.proxies.Proxy;
import java.util.*;
@@ -93,4 +94,6 @@ public boolean isAbort() {
String getHelpId();
void init(Router router);
+
+ void init(Router router, Proxy proxy);
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginInterceptor.java
index b5dc104786..3e4f3d689e 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginInterceptor.java
@@ -14,11 +14,12 @@
package com.predic8.membrane.core.interceptor.authentication.session;
import com.predic8.membrane.annot.*;
+import com.predic8.membrane.core.config.ProxyAware;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.http.*;
import com.predic8.membrane.core.interceptor.*;
import com.predic8.membrane.core.interceptor.authentication.session.SessionManager.*;
-import com.predic8.membrane.core.proxies.*;
+import com.predic8.membrane.core.proxies.Proxy;
import com.predic8.membrane.core.util.*;
import org.slf4j.*;
@@ -93,7 +94,7 @@
* @topic 3. Security and Validation
*/
@MCElement(name="login")
-public class LoginInterceptor extends AbstractInterceptor {
+public class LoginInterceptor extends AbstractInterceptor implements ProxyAware {
private static final Logger log = LoggerFactory.getLogger(LoginInterceptor.class.getName());
@@ -105,6 +106,7 @@ public class LoginInterceptor extends AbstractInterceptor {
private SessionManager sessionManager;
private AccountBlocker accountBlocker;
private LoginDialog loginDialog;
+ private Proxy proxy;
@Override
public void init() {
@@ -134,7 +136,6 @@ public void init() {
}
public String getBasePath() {
- Proxy proxy = getProxy();
if (proxy == null)
return "";
if (proxy.getKey().getPath() == null || proxy.getKey().isPathRegExp())
@@ -297,4 +298,9 @@ public void setMessage(String message) {
public String getDisplayName() {
return "login";
}
+
+ @Override
+ public void setProxy(Proxy proxy) {
+ this.proxy = proxy;
+ }
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/flow/AbstractFlowInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/flow/AbstractFlowInterceptor.java
index 57dadc96bd..edee39ebb0 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/flow/AbstractFlowInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/flow/AbstractFlowInterceptor.java
@@ -14,9 +14,12 @@
package com.predic8.membrane.core.interceptor.flow;
+import com.predic8.membrane.core.Router;
+import com.predic8.membrane.core.config.ProxyAware;
import com.predic8.membrane.core.exchange.Exchange;
import com.predic8.membrane.core.interceptor.AbstractInterceptor;
import com.predic8.membrane.core.interceptor.Interceptor;
+import com.predic8.membrane.core.proxies.Proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,4 +58,14 @@ protected static void createProblemDetails(String flow, Interceptor interceptor,
.exception(e)
.buildAndSetResponse(exc);
}
+
+ @Override
+ public void init(Router router, Proxy proxy) {
+ for (Interceptor i : interceptors) {
+ if(i instanceof ProxyAware pa) {
+ pa.setProxy(proxy);
+ }
+ }
+ init(router);
+ }
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/groovy/GroovyInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/groovy/GroovyInterceptor.java
index 036f403cb6..07da5409be 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/groovy/GroovyInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/groovy/GroovyInterceptor.java
@@ -15,8 +15,10 @@
package com.predic8.membrane.core.interceptor.groovy;
import com.predic8.membrane.annot.*;
+import com.predic8.membrane.core.config.ProxyAware;
import com.predic8.membrane.core.lang.*;
import com.predic8.membrane.core.lang.groovy.*;
+import com.predic8.membrane.core.proxies.Proxy;
import com.predic8.membrane.core.util.ConfigurationException;
import org.codehaus.groovy.control.*;
import org.codehaus.groovy.control.messages.*;
@@ -36,7 +38,7 @@
* @topic 2. Enterprise Integration Patterns
*/
@MCElement(name = "groovy", mixed = true)
-public class GroovyInterceptor extends AbstractScriptInterceptor {
+public class GroovyInterceptor extends AbstractScriptInterceptor implements ProxyAware {
private static final Logger log = LoggerFactory.getLogger(GroovyInterceptor.class);
@@ -44,6 +46,8 @@ public GroovyInterceptor() {
name = "groovy";
}
+ private Proxy proxy;
+
@Override
public EnumSet getAppliedFlow() {
return REQUEST_RESPONSE_ABORT_FLOW;
@@ -60,7 +64,7 @@ protected void initInternal() {
}
private void logGroovyError(MultipleCompilationErrorsException e) {
- log.error("Error in Groovy script in API '{}' with source: {}", getProxy().getName(),src);
+ log.error("Error in Groovy script in API '{}' with source: {}", proxy.getName(), src);
for(Message error : e.getErrorCollector().getErrors()) {
ByteArrayOutputStream bais = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(bais);
@@ -82,4 +86,10 @@ public String getLongDescription() {
escapeHtml4(src.stripIndent()) +
"";
}
+
+ @Override
+ public void setProxy(Proxy proxy) {
+ this.proxy = proxy;
+ }
+
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/OAuth2AuthorizationServerInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/OAuth2AuthorizationServerInterceptor.java
index c4afc96cce..de073c53b3 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/OAuth2AuthorizationServerInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/OAuth2AuthorizationServerInterceptor.java
@@ -14,6 +14,7 @@
package com.predic8.membrane.core.interceptor.oauth2;
import com.predic8.membrane.annot.*;
+import com.predic8.membrane.core.config.ProxyAware;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.interceptor.*;
import com.predic8.membrane.core.interceptor.authentication.session.*;
@@ -30,7 +31,7 @@
@SuppressWarnings("LoggingSimilarMessage")
@MCElement(name = "oauth2authserver")
-public class OAuth2AuthorizationServerInterceptor extends AbstractInterceptor {
+public class OAuth2AuthorizationServerInterceptor extends AbstractInterceptor implements ProxyAware {
private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationServerInterceptor.class.getName());
public static final Set<@NotNull String> SUPPORTED_AUTHORIZATION_GRANTS = Set.of("code", "token", "id_token token");
@@ -63,6 +64,8 @@ public class OAuth2AuthorizationServerInterceptor extends AbstractInterceptor {
private WellknownFile wellknownFile = new WellknownFile();
private ConsentPageFile consentPageFile = new ConsentPageFile();
+ private Proxy proxy;
+
@Override
public void init() {
super.init();
@@ -414,7 +417,6 @@ public void setRefreshTokenConfig(RefreshTokenConfig refreshTokenConfig) {
}
public String computeBasePath() {
- Proxy proxy = getProxy();
if (proxy == null)
return "";
if (proxy.getKey().getPath() == null || proxy.getKey().isPathRegExp())
@@ -425,4 +427,9 @@ public String computeBasePath() {
public String getBasePath() {
return basePath;
}
+
+ @Override
+ public void setProxy(Proxy proxy) {
+ this.proxy = proxy;
+ }
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java
index f183ae349d..4abb83b8b1 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java
@@ -66,6 +66,8 @@ public class ValidatorInterceptor extends AbstractInterceptor implements Applica
private ResolverMap resourceResolver;
private ApplicationContext applicationContext;
+ private SOAPProxy soapProxy;
+
public ValidatorInterceptor() {
name = "validator";
}
@@ -111,12 +113,10 @@ private MessageValidator getMessageValidator() throws Exception {
}
private @Nullable WSDLValidator getWsdlValidatorFromSOAPProxy() {
- if (router.getParentProxy(this) instanceof SOAPProxy sp) {
- wsdl = sp.getWsdl();
- name = "soap validator";
- return new WSDLValidator(resourceResolver, combine(getBaseLocation(), wsdl), serviceName, createFailureHandler(), skipFaults);
- }
- return null;
+ if(soapProxy == null) return null;
+ wsdl = soapProxy.getWsdl();
+ name = "soap validator";
+ return new WSDLValidator(resourceResolver, combine(getBaseLocation(), wsdl), serviceName, createFailureHandler(), skipFaults);
}
private @Nullable String getBaseLocation() {
@@ -319,4 +319,8 @@ private FailureHandler createFailureHandler() {
throw new IllegalArgumentException("Unknown failureHandler type: " + failureHandler);
}
+ public void setSoapProxy(SOAPProxy soapProxy) {
+ this.soapProxy = soapProxy;
+ }
+
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONSchemaVersionParser.java b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONSchemaVersionParser.java
index c5fe867ebc..7ba2597ba3 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONSchemaVersionParser.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONSchemaVersionParser.java
@@ -18,23 +18,23 @@
import com.predic8.membrane.core.util.*;
import org.jetbrains.annotations.*;
-import static com.networknt.schema.SchemaId.*;
+import static com.networknt.schema.SpecificationVersion.*;
public class JSONSchemaVersionParser {
- public static SpecVersion.VersionFlag parse(String version) {
- return SpecVersion.VersionFlag.fromId(aliasToSpecId(version)).get();
+ public static SpecificationVersion parse(String version) {
+ return aliasToSpecId(version);
}
- static @NotNull String aliasToSpecId(String alias) {
+ static @NotNull SpecificationVersion aliasToSpecId(String alias) {
if (alias == null)
throw new ConfigurationException("Unknown JSON Schema version: " + alias);
return switch (alias) {
- case "04","draft-04" -> V4;
- case "06","draft-06" -> V6;
- case "07","draft-07" -> V7;
- case "2019-09" -> V201909;
- case "2020-12" -> V202012;
+ case "04","draft-04" -> DRAFT_4;
+ case "06","draft-06" -> DRAFT_6;
+ case "07","draft-07" -> DRAFT_7;
+ case "2019-09" -> DRAFT_2019_09;
+ case "2020-12" -> DRAFT_2020_12;
default -> throw new ConfigurationException("Unknown JSON Schema version: " + alias);
};
}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONYAMLSchemaValidator.java b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONYAMLSchemaValidator.java
index 15b3b8ca3c..de3de379f2 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONYAMLSchemaValidator.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/json/JSONYAMLSchemaValidator.java
@@ -18,7 +18,10 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
+import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.networknt.schema.*;
+import com.networknt.schema.Error;
+import com.networknt.schema.path.NodePath;
import com.networknt.schema.serialization.YamlMapperFactory;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.interceptor.Interceptor.*;
@@ -30,7 +33,11 @@
import org.slf4j.*;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.charset.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.*;
@@ -44,8 +51,10 @@
public class JSONYAMLSchemaValidator extends AbstractMessageValidator {
private static final Logger log = LoggerFactory.getLogger(JSONYAMLSchemaValidator.class);
+
private final YAMLFactory factory = YAMLFactory.builder().enable(STRICT_DUPLICATE_DETECTION).build();
- private final ObjectMapper objectMapper = new ObjectMapper(factory);
+ private final ObjectMapper yamlObjectMapper = new ObjectMapper(factory);
+ private final ObjectMapper jsonObjectMapper = new ObjectMapper();
public static final String SCHEMA_VERSION_2020_12 = "2020-12";
@@ -55,19 +64,17 @@ public class JSONYAMLSchemaValidator extends AbstractMessageValidator {
private final AtomicLong valid = new AtomicLong();
private final AtomicLong invalid = new AtomicLong();
- private final SpecVersion.VersionFlag schemaId;
+ private final SpecificationVersion schemaId;
/**
* JsonSchemaFactory instances are thread-safe provided its configuration is not modified.
*/
- JsonSchemaFactory jsonSchemaFactory;
-
- SchemaValidatorsConfig config;
+ SchemaRegistry jsonSchemaFactory;
/**
* JsonSchema instances are thread-safe provided its configuration is not modified.
*/
- JsonSchema schema;
+ Schema schema;
InputFormat inputFormat;
@@ -96,22 +103,15 @@ public String getName() {
public void init() {
super.init();
- jsonSchemaFactory = JsonSchemaFactory.getInstance(schemaId, builder ->
- builder.schemaLoaders(loaders -> loaders.add(new MembraneSchemaLoader(resolver)))
- // builder.schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://www.example.org/", "classpath:/"))
- );
-
- SchemaValidatorsConfig.Builder builder = SchemaValidatorsConfig.builder();
- // By default the JDK regular expression implementation which is not ECMA 262 compliant is used
- // Note that setting this requires including optional dependencies
- // builder.regularExpressionFactory(GraalJSRegularExpressionFactory.getInstance());
- // builder.regularExpressionFactory(JoniRegularExpressionFactory.getInstance());
- config = builder.build();
-
- // If the schema data does not specify an $id the absolute IRI of the schema location will be used as the $id.
- schema= jsonSchemaFactory.getSchema(SchemaLocation.of( jsonSchema), config);
- schema.initializeValidators();
+ jsonSchemaFactory = SchemaRegistry.withDefaultDialect(schemaId, builder ->
+ builder.schemaLoader(loaders -> new MembraneSchemaLoader(resolver)));
+ try (InputStream in = resolver.resolve(jsonSchema)) {
+ schema = jsonSchemaFactory.getSchema((jsonSchema.endsWith(".yaml") || jsonSchema.endsWith(".yml") ? yamlObjectMapper: jsonObjectMapper).readTree(in));
+ schema.initializeValidators();
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot read JSON Schema from: " + jsonSchema, e);
+ }
}
public Outcome validateMessage(Exchange exc, Flow flow) throws Exception {
@@ -120,7 +120,7 @@ public Outcome validateMessage(Exchange exc, Flow flow) throws Exception {
public Outcome validateMessage(Exchange exc, Flow flow, Charset ignored) throws Exception {
- Set assertions = inputFormat == YAML ?
+ List assertions = inputFormat == YAML ?
handleMultipleYAMLDocuments(exc, flow) :
schema.validate(exc.getMessage(flow).getBodyAsStringDecoded(), inputFormat);
@@ -151,36 +151,34 @@ public Outcome validateMessage(Exchange exc, Flow flow, Charset ignored) throws
* If you call schema.validate(..) on a multi-document YAML, only the first document is validated. Therefore, we have
* to loop here ourselves.
*/
- private @NotNull Set handleMultipleYAMLDocuments(Exchange exc, Flow flow) throws IOException {
- Set assertions;
- assertions = new LinkedHashSet<>();
+ private @NotNull List handleMultipleYAMLDocuments(Exchange exc, Flow flow) throws IOException {
+ List assertions;
+ assertions = new ArrayList<>();
YAMLParser parser = factory.createParser(exc.getMessage(flow).getBodyAsStreamDecoded());
while (!parser.isClosed()) {
- assertions.addAll(schema.validate(objectMapper.readTree(parser)));
+ assertions.addAll(schema.validate(yamlObjectMapper.readTree(parser)));
parser.nextToken();
}
return assertions;
}
- private @NotNull List