From 264685372fa5bbe1c939e290641ea2a62979dfe6 Mon Sep 17 00:00:00 2001 From: Torben Burchgart Date: Mon, 19 Aug 2024 13:15:58 +0200 Subject: [PATCH 1/7] - Introduce a configurable path for the OTLP exporter in `OtlpExporter`. - Update endpoint URL generation to accommodate custom paths. - Implement logging functionality in `OpenTelemetryInterceptor` for missing OpenAPI records. --- .../OpenTelemetryInterceptor.java | 15 ++++++++++++--- .../opentelemetry/exporter/OtlpExporter.java | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java index 840f01a8b..a417bb2ce 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java @@ -21,6 +21,7 @@ import com.predic8.membrane.core.http.Header; import com.predic8.membrane.core.http.HeaderField; import com.predic8.membrane.core.interceptor.AbstractInterceptor; +import com.predic8.membrane.core.interceptor.InterceptorFlowController; import com.predic8.membrane.core.interceptor.Outcome; import com.predic8.membrane.core.interceptor.opentelemetry.exporter.OtelExporter; import com.predic8.membrane.core.interceptor.opentelemetry.exporter.OtlpExporter; @@ -33,6 +34,8 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE; import static com.predic8.membrane.core.interceptor.opentelemetry.HTTPTraceContextUtil.getContextFromRequestHeader; @@ -55,6 +58,8 @@ public class OpenTelemetryInterceptor extends AbstractInterceptor { private boolean logBody = false; + private static final Logger log = LoggerFactory.getLogger(OpenTelemetryInterceptor.class); + @Override public void init() throws Exception { otel = OpenTelemetryConfigurator.openTelemetry("Membrane", exporter, getSampleRate()); @@ -127,10 +132,14 @@ private static void setSpanHttpHeaderAttributes(Header header, Span span) { } private void setSpanOpenAPIAttributes(Exchange exc, Span span) { - OpenAPIRecord record = exc.getProperty(OPENAPI_RECORD, OpenAPIRecord.class); - if (record != null) { - span.setAttribute("openapi.title", record.getApi().getInfo().getTitle()); + OpenAPIRecord record; + try { + record = exc.getProperty(OPENAPI_RECORD, OpenAPIRecord.class); + } catch (ClassCastException e) { + log.info("No OpenAPI to report to OpenTelemetry."); + return; } + span.setAttribute("openapi.title", record.getApi().getInfo().getTitle()); } private String getSpanName(Exchange exc) { diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/exporter/OtlpExporter.java b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/exporter/OtlpExporter.java index a0d9cdc8e..91a1e3d3a 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/exporter/OtlpExporter.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/exporter/OtlpExporter.java @@ -39,17 +39,22 @@ public class OtlpExporter implements OtelExporter { private static final int TIMEOUT_SECONDS = 30; private String host = "localhost"; private Integer port; + private String path = ""; private OtlpType transport = GRPC; private final List headers = new ArrayList<>(); private boolean secured = false; public String getEndpointUrl() { - String endpoint = format("%s://%s:%d", isSecured() ? "https" : "http", host, getProtocolPort(port, transport)); - if (transport == HTTP) { - endpoint += "/v1/traces"; + return format("%s://%s:%d%s", isSecured() ? "https" : "http", host, getProtocolPort(port, transport), getPathExtension()); + } + + @SuppressWarnings("StringEquality") + private String getPathExtension() { + if (path == "" && transport == HTTP) { + return "/v1/traces"; } - return endpoint; + return path; } private int getProtocolPort(Integer port, OtlpType trans) { @@ -114,6 +119,9 @@ public void setSecured(boolean secured) { this.secured = secured; } + @MCAttribute + public void setPath(String path) { this.path = path; } + @MCAttribute public void setHost(String host) { this.host = host; @@ -124,6 +132,8 @@ public void setPort(int port) { this.port = port; } + public String getPath() { return path; } + @Override public String getHost() { return host; From dfe6e86c35b14d9631a454eed64cafa067e9d945 Mon Sep 17 00:00:00 2001 From: Torben Burchgart Date: Mon, 19 Aug 2024 17:11:34 +0200 Subject: [PATCH 2/7] Add null check for record in OpenTelemetryInterceptor before accessing attributes --- .../interceptor/opentelemetry/OpenTelemetryInterceptor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java index a417bb2ce..44925c6bd 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java @@ -139,7 +139,9 @@ record = exc.getProperty(OPENAPI_RECORD, OpenAPIRecord.class); log.info("No OpenAPI to report to OpenTelemetry."); return; } - span.setAttribute("openapi.title", record.getApi().getInfo().getTitle()); + if (record != null) { + span.setAttribute("openapi.title", record.getApi().getInfo().getTitle()); + } } private String getSpanName(Exchange exc) { From 571c59741b8edf63abd22329ecc76428ce86c587 Mon Sep 17 00:00:00 2001 From: Torben Burchgart Date: Mon, 19 Aug 2024 17:12:16 +0200 Subject: [PATCH 3/7] Change log level of missing OpenAPI info --- .../interceptor/opentelemetry/OpenTelemetryInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java index 44925c6bd..647c83354 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java @@ -136,7 +136,7 @@ private void setSpanOpenAPIAttributes(Exchange exc, Span span) { try { record = exc.getProperty(OPENAPI_RECORD, OpenAPIRecord.class); } catch (ClassCastException e) { - log.info("No OpenAPI to report to OpenTelemetry."); + log.debug("No OpenAPI to report to OpenTelemetry."); return; } if (record != null) { From e9f52e89649da4c07b3086ffaaf2a1ae6c2a9e8e Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 20 Aug 2024 06:57:43 +0000 Subject: [PATCH 4/7] Release 5.7.1 --- annot/pom.xml | 2 +- core/.factorypath | 2 +- core/pom.xml | 2 +- distribution/examples/embedding-java/pom.xml | 2 +- distribution/examples/stax-interceptor/pom.xml | 2 +- distribution/pom.xml | 2 +- maven-plugin/pom.xml | 2 +- membrane.spec | 2 +- pom.xml | 2 +- starter/pom.xml | 2 +- test/pom.xml | 2 +- war/.factorypath | 2 +- war/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/annot/pom.xml b/annot/pom.xml index 916f7ad2e..091d55bc9 100644 --- a/annot/pom.xml +++ b/annot/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/core/.factorypath b/core/.factorypath index 5ecb7bda3..0c8aeda4a 100644 --- a/core/.factorypath +++ b/core/.factorypath @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index bb05b1d8a..838037eba 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/distribution/examples/embedding-java/pom.xml b/distribution/examples/embedding-java/pom.xml index 394f36104..9b7158e2d 100644 --- a/distribution/examples/embedding-java/pom.xml +++ b/distribution/examples/embedding-java/pom.xml @@ -29,7 +29,7 @@ org.membrane-soa service-proxy-core - 5.7.1-SNAPSHOT + 5.7.1 org.projectlombok diff --git a/distribution/examples/stax-interceptor/pom.xml b/distribution/examples/stax-interceptor/pom.xml index b88144911..5966a4eb8 100644 --- a/distribution/examples/stax-interceptor/pom.xml +++ b/distribution/examples/stax-interceptor/pom.xml @@ -19,7 +19,7 @@ org.membrane-soa service-proxy-core - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/distribution/pom.xml b/distribution/pom.xml index ec3aae1a5..46423985e 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -27,7 +27,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/maven-plugin/pom.xml b/maven-plugin/pom.xml index 942c5f78e..3c3af42d2 100644 --- a/maven-plugin/pom.xml +++ b/maven-plugin/pom.xml @@ -25,7 +25,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/membrane.spec b/membrane.spec index 020073d0c..a3dfbb8ac 100644 --- a/membrane.spec +++ b/membrane.spec @@ -4,7 +4,7 @@ %global logdir %{_var}/log/%{name} Name: membrane -Version: 5.7.1-SNAPSHOT +Version: 5.7.1 Release: 1%{?dist} URL: https://github.com/membrane/api-gateway Summary: Membrane - Open Source API Gateway written in Java for REST APIs, WebSockets, STOMP and legacy Web Services diff --git a/pom.xml b/pom.xml index d6a64242d..4548e1982 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 4.0.0 org.membrane-soa service-proxy-parent - 5.7.1-SNAPSHOT + 5.7.1 ${project.artifactId} Membrane is an open source API Gateway written in Java that features: - OpenAPI support with validation diff --git a/starter/pom.xml b/starter/pom.xml index 509f4ab7c..5e8560043 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -2,7 +2,7 @@ service-proxy-parent org.membrane-soa - 5.7.1-SNAPSHOT + 5.7.1 4.0.0 diff --git a/test/pom.xml b/test/pom.xml index 925604de3..0c77d6fa2 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 diff --git a/war/.factorypath b/war/.factorypath index 5ecb7bda3..0c8aeda4a 100644 --- a/war/.factorypath +++ b/war/.factorypath @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/war/pom.xml b/war/pom.xml index 6019bebef..1fc582a08 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1-SNAPSHOT + 5.7.1 From 8ff774eb4056ab653b38f32327d183bfa299f072 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 20 Aug 2024 07:44:26 +0000 Subject: [PATCH 5/7] Snapshot version --- annot/pom.xml | 2 +- core/.factorypath | 2 +- core/pom.xml | 2 +- distribution/examples/embedding-java/pom.xml | 2 +- distribution/examples/stax-interceptor/pom.xml | 2 +- distribution/pom.xml | 2 +- maven-plugin/pom.xml | 2 +- membrane.spec | 2 +- pom.xml | 2 +- starter/pom.xml | 2 +- test/pom.xml | 2 +- war/.factorypath | 2 +- war/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/annot/pom.xml b/annot/pom.xml index 091d55bc9..abb9b6636 100644 --- a/annot/pom.xml +++ b/annot/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/core/.factorypath b/core/.factorypath index 0c8aeda4a..00699f739 100644 --- a/core/.factorypath +++ b/core/.factorypath @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index 838037eba..44dceec9e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/distribution/examples/embedding-java/pom.xml b/distribution/examples/embedding-java/pom.xml index 9b7158e2d..022e4460d 100644 --- a/distribution/examples/embedding-java/pom.xml +++ b/distribution/examples/embedding-java/pom.xml @@ -29,7 +29,7 @@ org.membrane-soa service-proxy-core - 5.7.1 + 5.7.2-SNAPSHOT org.projectlombok diff --git a/distribution/examples/stax-interceptor/pom.xml b/distribution/examples/stax-interceptor/pom.xml index 5966a4eb8..179e934f1 100644 --- a/distribution/examples/stax-interceptor/pom.xml +++ b/distribution/examples/stax-interceptor/pom.xml @@ -19,7 +19,7 @@ org.membrane-soa service-proxy-core - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/distribution/pom.xml b/distribution/pom.xml index 46423985e..2a99efa78 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -27,7 +27,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/maven-plugin/pom.xml b/maven-plugin/pom.xml index 3c3af42d2..bb8c6b831 100644 --- a/maven-plugin/pom.xml +++ b/maven-plugin/pom.xml @@ -25,7 +25,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/membrane.spec b/membrane.spec index a3dfbb8ac..7e73032e4 100644 --- a/membrane.spec +++ b/membrane.spec @@ -4,7 +4,7 @@ %global logdir %{_var}/log/%{name} Name: membrane -Version: 5.7.1 +Version: 5.7.2-SNAPSHOT Release: 1%{?dist} URL: https://github.com/membrane/api-gateway Summary: Membrane - Open Source API Gateway written in Java for REST APIs, WebSockets, STOMP and legacy Web Services diff --git a/pom.xml b/pom.xml index 4548e1982..4b0f65232 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 4.0.0 org.membrane-soa service-proxy-parent - 5.7.1 + 5.7.2-SNAPSHOT ${project.artifactId} Membrane is an open source API Gateway written in Java that features: - OpenAPI support with validation diff --git a/starter/pom.xml b/starter/pom.xml index 5e8560043..58c9622d6 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -2,7 +2,7 @@ service-proxy-parent org.membrane-soa - 5.7.1 + 5.7.2-SNAPSHOT 4.0.0 diff --git a/test/pom.xml b/test/pom.xml index 0c77d6fa2..ac56e67b8 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT diff --git a/war/.factorypath b/war/.factorypath index 0c8aeda4a..00699f739 100644 --- a/war/.factorypath +++ b/war/.factorypath @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/war/pom.xml b/war/pom.xml index 1fc582a08..f1e183298 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -23,7 +23,7 @@ org.membrane-soa service-proxy-parent ../pom.xml - 5.7.1 + 5.7.2-SNAPSHOT From 7581b0288b59b64d561d7defb8f61aee304a0cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6rdes?= <118011644+christiangoerdes@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:32:26 +0200 Subject: [PATCH 6/7] #1201 static content plugin (#1228) * infra (wip) * refactoring (wip) * added prettifyXML * requested changes * enhanced code and tests * Refactoring --------- Co-authored-by: t-burch <119930761+t-burch@users.noreply.github.com> --- .../templating/StaticInterceptor.java | 144 +++++++++++ .../templating/TemplateInterceptor.java | 132 ++-------- .../core/transport/ssl/PEMSupport.java | 23 +- .../predic8/membrane/core/util/TextUtil.java | 58 +++++ .../templating/StaticInterceptorTest.java | 10 + .../membrane/core/util/TextUtilTest.java | 238 +++++++++++++----- 6 files changed, 421 insertions(+), 184 deletions(-) create mode 100644 core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java create mode 100644 core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java new file mode 100644 index 000000000..e35102ff3 --- /dev/null +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java @@ -0,0 +1,144 @@ +package com.predic8.membrane.core.interceptor.templating; + +import com.predic8.membrane.annot.MCAttribute; +import com.predic8.membrane.annot.MCElement; +import com.predic8.membrane.annot.MCTextContent; +import com.predic8.membrane.core.beautifier.JSONBeautifier; +import com.predic8.membrane.core.exchange.Exchange; +import com.predic8.membrane.core.http.Message; +import com.predic8.membrane.core.interceptor.AbstractInterceptor; +import com.predic8.membrane.core.interceptor.Outcome; +import com.predic8.membrane.core.util.TextUtil; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.StringReader; + +import static com.predic8.membrane.core.http.MimeType.*; +import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE; +import static com.predic8.membrane.core.util.TextUtil.unifyIndent; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; + +@MCElement(name = "static", mixed = true) +public class StaticInterceptor extends AbstractInterceptor { + + protected String location; + + protected String textTemplate; + + protected String contentType = TEXT_PLAIN; + + protected Boolean pretty = false; + + protected final JSONBeautifier jsonBeautifier = new JSONBeautifier(); + + protected static final Logger log = LoggerFactory.getLogger("StaticInterceptor"); + + public StaticInterceptor() { + name = "Static"; + } + + @Override + public Outcome handleRequest(Exchange exc) throws Exception { + return handleInternal(exc.getRequest()); + } + + @Override + public Outcome handleResponse(Exchange exc) throws Exception { + return handleInternal(exc.getResponse()); + } + + private Outcome handleInternal(Message msg) { + msg.setBodyContent(getTemplateBytes()); + msg.getHeader().setContentType(getContentType()); + return CONTINUE; + } + + private byte @NotNull [] getTemplateBytes() { + if (!pretty) + return textTemplate.getBytes(UTF_8); + + return switch (contentType) { + case APPLICATION_JSON -> prettifyJson(textTemplate).getBytes(UTF_8); + case APPLICATION_XML, APPLICATION_SOAP, TEXT_HTML, TEXT_XML, TEXT_HTML_UTF8, TEXT_XML_UTF8 -> prettifyXML(textTemplate).getBytes(UTF_8); + default -> unifyIndent(textTemplate).getBytes(UTF_8); + }; + } + + private String prettifyXML(String text) { + try { + return TextUtil.formatXML(new StringReader(text)); + } catch (Exception e) { + log.warn("Failed to format XML", e); + return text; + } + } + + String prettifyJson(String text) { + try { + return jsonBeautifier.beautify(text); + } catch (IOException e) { + log.warn("Failed to format JSON", e); + return text; + } + } + + @Override + public void init() throws Exception { + if (this.getLocation() != null && (getTextTemplate() != null && !getTextTemplate().isBlank())) { + throw new IllegalStateException("On <" + getName() + ">, ./text() and ./@location cannot be set at the same time."); + } + } + + public String getLocation() { + return location; + } + + @MCAttribute + public void setLocation(String location){ + this.location = location; + } + + public String getTextTemplate() { + return textTemplate; + } + + @MCTextContent + public void setTextTemplate(String textTemplate) { + this.textTemplate = textTemplate; + } + + protected String getName() { + return getClass().getAnnotation(MCElement.class).name(); + } + + public String getContentType() { + return contentType; + } + + @MCAttribute + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public Boolean getPretty() { + return pretty; + } + + @MCAttribute + public void setPretty(String pretty) { + this.pretty = Boolean.valueOf(pretty); + } + + private String formatAsHtml(String plaintext) { + return String.join("
", escapeHtml4(plaintext).split("\n")); + } + + @Override + public String getShortDescription() { + return formatAsHtml(textTemplate); + } +} diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java index cfcd399bd..a2002cbfb 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java @@ -14,27 +14,27 @@ package com.predic8.membrane.core.interceptor.templating; -import com.predic8.membrane.annot.*; -import com.predic8.membrane.core.beautifier.*; -import com.predic8.membrane.core.exceptions.*; -import com.predic8.membrane.core.exchange.*; -import com.predic8.membrane.core.http.*; -import com.predic8.membrane.core.interceptor.*; -import com.predic8.membrane.core.lang.*; -import com.predic8.membrane.core.resolver.*; -import groovy.text.*; -import org.apache.commons.io.*; -import org.apache.commons.lang3.*; -import org.slf4j.*; - -import java.io.*; -import java.util.*; +import com.predic8.membrane.annot.MCElement; +import com.predic8.membrane.core.exceptions.ProblemDetails; +import com.predic8.membrane.core.exchange.Exchange; +import com.predic8.membrane.core.http.Message; +import com.predic8.membrane.core.interceptor.Outcome; +import com.predic8.membrane.core.lang.ScriptingUtils; +import com.predic8.membrane.core.resolver.ResolverMap; +import groovy.text.StreamingTemplateEngine; +import groovy.text.Template; +import groovy.text.TemplateExecutionException; +import groovy.text.XmlTemplateEngine; +import org.apache.commons.io.FilenameUtils; + +import java.io.InputStreamReader; +import java.util.HashMap; import static com.predic8.membrane.core.http.MimeType.*; -import static com.predic8.membrane.core.interceptor.Interceptor.Flow.*; -import static com.predic8.membrane.core.interceptor.Outcome.*; -import static java.nio.charset.StandardCharsets.*; -import static org.apache.commons.text.StringEscapeUtils.*; +import static com.predic8.membrane.core.interceptor.Interceptor.Flow.REQUEST; +import static com.predic8.membrane.core.interceptor.Interceptor.Flow.RESPONSE; +import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE; +import static java.nio.charset.StandardCharsets.UTF_8; /** * @description Renders the body content of a message from a template. The template can @@ -48,25 +48,12 @@ @MCElement(name="template", mixed = true) -public class TemplateInterceptor extends AbstractInterceptor{ - - /** - * @description Path of template file - */ - private String location; - - private String textTemplate; - - private Template template; - - private String contentType = TEXT_PLAIN; - - private Boolean pretty = false; - - private final JSONBeautifier jsonBeautifier = new JSONBeautifier(); +public class TemplateInterceptor extends StaticInterceptor { private boolean scriptAccessesJson; + protected Template template; + public TemplateInterceptor() { name = "Template"; } @@ -97,14 +84,6 @@ private Outcome handleInternal(Message msg, Exchange exc, Flow flow) { return CONTINUE; } - String prettifyJson(String text) { - try { - return jsonBeautifier.beautify(text); - } catch (IOException e) { - return text; - } - } - @SuppressWarnings("RedundantThrows") // Declaration of exception is needed. However, Groovy does not declare it. private String fillTemplate(Exchange exc, Message msg, Flow flow) throws TemplateExecutionException { @@ -155,32 +134,6 @@ public void init() throws Exception { throw new IllegalStateException("You have to set either ./@location or ./text()"); } - public String getLocation() { - return location; - } - - /** - * @description path of xml template file. - * @example template.xml - */ - @MCAttribute - public void setLocation(String location){ - this.location = location; - } - - public String getTextTemplate() { - return textTemplate; - } - - @MCTextContent - public void setTextTemplate(String textTemplate) throws IOException, ClassNotFoundException { - this.textTemplate = textTemplate; - - if(textTemplate != null && !StringUtils.isBlank(textTemplate)){ - template = new StreamingTemplateEngine().createTemplate(this.getTextTemplate()); - } - } - public Template getTemplate() { return template; } @@ -188,45 +141,4 @@ public Template getTemplate() { public void setTemplate(Template template) { this.template = template; } - - - private String getName() { - return getClass().getAnnotation(MCElement.class).name(); - } - - public String getContentType() { - return contentType; - } - - /** - * @description content type for body - * @example application/json - */ - @MCAttribute - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public Boolean getPretty() { - return pretty; - } - - /** - * @description Format JSON documents. - * @example yes - * @default no - */ - @MCAttribute - public void setPretty(String pretty) { - this.pretty = Boolean.valueOf(pretty); - } - - private String formatAsHtml(String plaintext) { - return String.join("
", escapeHtml4(plaintext).split("\n")); - } - - @Override - public String getShortDescription() { - return formatAsHtml(textTemplate); - } } \ No newline at end of file diff --git a/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java b/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java index e2bf4fa74..21b74f207 100644 --- a/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java +++ b/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java @@ -36,6 +36,8 @@ import java.util.List; import java.util.regex.Pattern; +import static com.predic8.membrane.core.util.TextUtil.unifyIndent; + public abstract class PEMSupport { private static final Logger log = LoggerFactory.getLogger(PEMSupport.class.getName()); @@ -64,21 +66,8 @@ public PEMSupportImpl() { Security.addProvider(new BouncyCastleProvider()); } - private String cleanupPEM(String pemBlock) { - String lines[] = pemBlock.split("\r?\n"); - StringBuilder block = new StringBuilder(); - for (String line : lines) { - String l = line.replaceAll("^\\s+", ""); - if (l.length() > 0) { - block.append(l); - block.append("\n"); - } - } - return block.toString(); - } - public X509Certificate parseCertificate(String pemBlock) throws IOException { - PEMParser p2 = new PEMParser(new StringReader(cleanupPEM(pemBlock))); + PEMParser p2 = new PEMParser(new StringReader(unifyIndent(pemBlock))); Object o2 = p2.readObject(); if (o2 == null) throw new InvalidParameterException("Could not read certificate. Expected the certificate to begin with '-----BEGIN CERTIFICATE-----'."); @@ -94,7 +83,7 @@ public X509Certificate parseCertificate(String pemBlock) throws IOException { } public List parseCertificates(String pemBlock) throws IOException { List res = new ArrayList<>(); - PEMParser p2 = new PEMParser(new StringReader(cleanupPEM(pemBlock))); + PEMParser p2 = new PEMParser(new StringReader(unifyIndent(pemBlock))); JcaX509CertificateConverter certconv = new JcaX509CertificateConverter().setProvider("BC"); while(true) { Object o2 = p2.readObject(); @@ -115,7 +104,7 @@ public List parseCertificates(String pemBlock) throws IOExcepti } public Key getPrivateKey(String pemBlock) throws IOException { - PEMParser p = new PEMParser(new StringReader(cleanupPEM(pemBlock))); + PEMParser p = new PEMParser(new StringReader(unifyIndent(pemBlock))); Object o = p.readObject(); if (o == null) throw new InvalidParameterException("Could not read certificate. Expected the certificate to begin with '-----BEGIN CERTIFICATE-----'."); @@ -131,7 +120,7 @@ public Key getPrivateKey(String pemBlock) throws IOException { } public Object parseKey(String pemBlock) throws IOException { - PEMParser p = new PEMParser(new StringReader(cleanupPEM(pemBlock))); + PEMParser p = new PEMParser(new StringReader(unifyIndent(pemBlock))); Object o = p.readObject(); if (o == null) { log.error("Could not read PEM file. Check the contents of PEM file or configuration. Content is {}", pemBlock); diff --git a/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java b/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java index bf981bff9..45f064c12 100644 --- a/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java +++ b/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java @@ -181,4 +181,62 @@ public static String getLineFromMultilineString(String s,int lineNumber) { public static String escapeQuotes(String s) { return s.replace("\"", "\\\""); } + + /** + * Adjusts the indentation of each line in a multiline string to match the minimum indentation found. + * + * @param multilineString The input multiline string to process. + * @return A string with adjusted indentation. + */ + public static String unifyIndent(String multilineString) { + String[] lines = multilineString.split("\r?\n"); + return trimLines(lines, getMinIndent(lines)).toString().replaceFirst("\\s*$", ""); + } + + /** + * Trims excess indentation from each line in the input array, based on a specified minimum indent level. + * + * @param lines The array of lines to process. + * @param minIndent The minimum indent level to maintain. + * @return A StringBuilder containing lines with adjusted indentation. + */ + public static StringBuilder trimLines(String[] lines, int minIndent) { + StringBuilder result = new StringBuilder(); + for (String line : lines) { + if (!line.trim().isEmpty()) { + result.append(" ".repeat(Math.max(getCurrentIndent(line) - minIndent, 0))).append(line.trim()).append("\n"); + } else { + result.append("\n"); + } + } + return result; + } + + /** + * Calculates the current indentation level (number of leading spaces) of a given line. + * + * @param line The line to calculate the indentation for. + * @return The number of leading spaces in the line. + */ + public static int getCurrentIndent(String line) { + return line.length() - line.replaceFirst("^\\s+", "").length(); + } + + /** + * Determines the minimum indentation level (number of leading spaces) across all non-empty lines in an array of lines. + * + * @param lines The array of lines to analyze. + * @return The minimum indent level found among the lines. + */ + public static int getMinIndent(String[] lines) { + int minIndent = Integer.MAX_VALUE; + for (String line : lines) { + if (!line.trim().isEmpty()) { + int leadingSpaces = getCurrentIndent(line); + minIndent = Math.min(minIndent, leadingSpaces); + } + } + return minIndent; + } + } diff --git a/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java new file mode 100644 index 000000000..9edfbf074 --- /dev/null +++ b/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java @@ -0,0 +1,10 @@ +package com.predic8.membrane.core.interceptor.templating; + +import org.junit.jupiter.api.Test; + +import static com.predic8.membrane.core.interceptor.templating.StaticInterceptor.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class StaticInterceptorTest { + +} \ No newline at end of file diff --git a/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java b/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java index a5ca5036b..fa192966f 100644 --- a/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java +++ b/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java @@ -14,6 +14,7 @@ package com.predic8.membrane.core.util; import static com.predic8.membrane.core.util.TextUtil.*; +import static java.lang.Integer.MAX_VALUE; import static org.junit.jupiter.api.Assertions.*; import java.util.regex.Pattern; @@ -23,58 +24,58 @@ public class TextUtilTest { - @Test - public void testGlobToExpStarPrefixHost() { - Pattern pattern = Pattern.compile(globToRegExp("*.predic8.de")); - assertTrue(pattern.matcher("hgsjagdjhsa.predic8.de").matches()); - assertTrue(pattern.matcher("jhkj.predic8.de").matches()); - assertFalse(pattern.matcher("jhkj.predic8.com").matches()); - } - - @Test - public void testGlobToExpStarSuffixHost() { - Pattern pattern = Pattern.compile(globToRegExp("predic8.*")); - assertTrue(pattern.matcher("predic8.de").matches()); - assertTrue(pattern.matcher("predic8.com").matches()); - assertFalse(pattern.matcher("jhkj.predic8.de").matches()); - } - - @Test - public void testGlobToExpStarInfixHost() { - Pattern pattern = Pattern.compile(globToRegExp("www.*.de")); - assertTrue(pattern.matcher("www.predic8.de").matches()); - assertTrue(pattern.matcher("www.oio.de").matches()); - assertFalse(pattern.matcher("www.predic8.com").matches()); - assertFalse(pattern.matcher("www.predic8.co.uk").matches()); - assertFalse(pattern.matcher("services.predic8.de").matches()); - } - - @Test - public void testGlobToExpStarPrefixIp() { - Pattern pattern = Pattern.compile(globToRegExp("*.68.5.122")); - assertTrue(pattern.matcher("192.68.5.122").matches()); - assertFalse(pattern.matcher("192.68.5.123").matches()); - } - - @Test - public void testGlobToExpStarSuffixIp() { - Pattern pattern = Pattern.compile(globToRegExp("192.68.7.*")); - assertTrue(pattern.matcher("192.68.7.12").matches()); - assertTrue(pattern.matcher("192.68.7.4").matches()); - assertFalse(pattern.matcher("192.68.6.12").matches()); - } - - @Test - public void testGlobToExpStarInfixIp() { - Pattern pattern = Pattern.compile(globToRegExp("192.68.*.15")); - assertTrue(pattern.matcher("192.68.5.15").matches()); - assertTrue(pattern.matcher("192.68.24.15").matches()); - assertFalse(pattern.matcher("192.68.24.12").matches()); - } + @Test + void testGlobToExpStarPrefixHost() { + Pattern pattern = Pattern.compile(globToRegExp("*.predic8.de")); + assertTrue(pattern.matcher("hgsjagdjhsa.predic8.de").matches()); + assertTrue(pattern.matcher("jhkj.predic8.de").matches()); + assertFalse(pattern.matcher("jhkj.predic8.com").matches()); + } + + @Test + void testGlobToExpStarSuffixHost() { + Pattern pattern = Pattern.compile(globToRegExp("predic8.*")); + assertTrue(pattern.matcher("predic8.de").matches()); + assertTrue(pattern.matcher("predic8.com").matches()); + assertFalse(pattern.matcher("jhkj.predic8.de").matches()); + } + + @Test + void testGlobToExpStarInfixHost() { + Pattern pattern = Pattern.compile(globToRegExp("www.*.de")); + assertTrue(pattern.matcher("www.predic8.de").matches()); + assertTrue(pattern.matcher("www.oio.de").matches()); + assertFalse(pattern.matcher("www.predic8.com").matches()); + assertFalse(pattern.matcher("www.predic8.co.uk").matches()); + assertFalse(pattern.matcher("services.predic8.de").matches()); + } + + @Test + void testGlobToExpStarPrefixIp() { + Pattern pattern = Pattern.compile(globToRegExp("*.68.5.122")); + assertTrue(pattern.matcher("192.68.5.122").matches()); + assertFalse(pattern.matcher("192.68.5.123").matches()); + } + + @Test + void testGlobToExpStarSuffixIp() { + Pattern pattern = Pattern.compile(globToRegExp("192.68.7.*")); + assertTrue(pattern.matcher("192.68.7.12").matches()); + assertTrue(pattern.matcher("192.68.7.4").matches()); + assertFalse(pattern.matcher("192.68.6.12").matches()); + } + + @Test + void testGlobToExpStarInfixIp() { + Pattern pattern = Pattern.compile(globToRegExp("192.68.*.15")); + assertTrue(pattern.matcher("192.68.5.15").matches()); + assertTrue(pattern.matcher("192.68.24.15").matches()); + assertFalse(pattern.matcher("192.68.24.12").matches()); + } @Test void getLineFromMultilineStringTest() { - assertEquals("ccc ccc",TextUtil.getLineFromMultilineString(""" + assertEquals("ccc ccc", TextUtil.getLineFromMultilineString(""" aaa aaa bb bb ccc ccc @@ -82,15 +83,138 @@ void getLineFromMultilineStringTest() { """, 3)); } - @Test - void getLineFromMultilineStringOneLine() { - assertEquals("aaa aaa",TextUtil.getLineFromMultilineString(""" + @Test + void getLineFromMultilineStringOneLine() { + assertEquals("aaa aaa", TextUtil.getLineFromMultilineString(""" aaa aaa """, 1)); - } + } + + @Test + void escapeQuoteSimple() { + assertEquals("Test text with \\\" quotes", escapeQuotes("Test text with \" quotes")); + } + + + @Test + void testUnifyIndent() { + assertEquals(""" + line1 + line2 + line3""", unifyIndent(""" + line1 + line2 + line3""")); + + assertEquals(""" + line1 + line2 + line3""", unifyIndent(""" + line1 + line2 + line3""")); + + assertEquals(""" + line1 + line2 + line3""", unifyIndent(""" + line1 + line2 + line3""")); + + assertEquals(""" + line1 + + line3""", unifyIndent(""" + line1 + + line3""")); + + assertEquals(""" + + line1 + line2 + line3""", unifyIndent(""" + + line1 + line2 + line3 + """)); + + assertEquals("", unifyIndent(""" + + + """)); + + assertEquals(""" + line1 + + line2""", unifyIndent(""" + line1\r + + line2""")); + + assertEquals(""" + line1 + line2""", unifyIndent(""" + \tline1 + \tline2""")); + + assertEquals(""" + line1 + + line2""", unifyIndent(""" + line1\r + + line2""")); + + assertEquals(""" + line1 + + line2""", unifyIndent(""" + line1\r + \r + line2""")); + + } - @Test - public void escapeQuoteSimple() { - assertEquals("Test text with \\\" quotes", escapeQuotes("Test text with \" quotes")); - } + @Test + void testTrimLines() { + assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{"Line1", "Line2", "Line3"}, 0).toString()); + assertEquals("Line1\n Line2\nLine3\n", trimLines(new String[]{" Line1", " Line2", " Line3"}, 4).toString()); + assertEquals(" Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1", "\tLine2", " Line3"}, 2).toString()); + assertEquals("\n\n\n", trimLines(new String[]{" ", "\t", " "}, 2).toString()); + assertEquals("\n\n\n", trimLines(new String[]{"", "", ""}, 0).toString()); + assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1", " Line2", " Line3"}, 6).toString()); + assertEquals("Line1\nLine2\n", trimLines(new String[]{" Line1\r", "\tLine2\r"}, 2).toString()); + assertEquals("Line1\nLine2\n", trimLines(new String[]{"\tLine1", "\tLine2"}, 1).toString()); + assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1\r", " Line2", " Line3"}, 2).toString()); + assertEquals("Line1\n\nLine3\n", trimLines(new String[]{" Line1", "", " Line3"}, 2).toString()); + } + + @Test + void testGetCurrentIndent() { + assertEquals(0, getCurrentIndent("NoIndentation")); + assertEquals(4, getCurrentIndent(" FourSpaces")); + assertEquals(3, getCurrentIndent("\t\t\tThreeTabs")); + assertEquals(5, getCurrentIndent(" \t \tMixedSpacesAndTabs")); + assertEquals(0, getCurrentIndent("")); + assertEquals(6, getCurrentIndent(" ")); + assertEquals(3, getCurrentIndent(" \rLineWithCarriageReturn")); + assertEquals(1, getCurrentIndent("\tLineWithTab")); + assertEquals(1, getCurrentIndent("\rLineStartsWithCarriageReturn")); + } + + @Test + void testGetMinIndent() { + assertEquals(0, getMinIndent(new String[]{"Line1", "Line2", "Line3"})); + assertEquals(2, getMinIndent(new String[]{" Line1", " Line2", " Line3"})); + assertEquals(1, getMinIndent(new String[]{" Line1", "\tLine2", " Line3"})); + assertEquals(MAX_VALUE, getMinIndent(new String[]{" ", "\t", ""})); + assertEquals(0, getMinIndent(new String[]{" Line1", "", " Line2", "Line3"})); + assertEquals(MAX_VALUE, getMinIndent(new String[]{"", " ", "\t"})); + assertEquals(2, getMinIndent(new String[]{" Line1\r", " Line2"})); + assertEquals(1, getMinIndent(new String[]{"\tLine1", " Line2"})); + assertEquals(0, getMinIndent(new String[]{"Line1\r", "\tLine2", "Line3"})); + } } \ No newline at end of file From 4be4b3025a1c4b56428d9b56b58f167f9ba417af Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Mon, 26 Aug 2024 09:53:34 +0200 Subject: [PATCH 7/7] fix: upgrade com.sun.xml.ws:jaxws-rt from 4.0.2 to 4.0.3 (#1236) Snyk has created this PR to upgrade com.sun.xml.ws:jaxws-rt from 4.0.2 to 4.0.3. See this package in maven: com.sun.xml.ws:jaxws-rt See this project in Snyk: https://app.snyk.io/org/predic8/project/765f16ed-43e4-495d-9200-44db199695d7?utm_source=github&utm_medium=referral&page=upgrade-pr Co-authored-by: snyk-bot Co-authored-by: t-burch <119930761+t-burch@users.noreply.github.com> --- distribution/examples/versioning/xslt/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/examples/versioning/xslt/pom.xml b/distribution/examples/versioning/xslt/pom.xml index 4c2b1b6d4..e04e446e8 100644 --- a/distribution/examples/versioning/xslt/pom.xml +++ b/distribution/examples/versioning/xslt/pom.xml @@ -22,7 +22,7 @@ com.sun.xml.ws jaxws-rt - 4.0.2 + 4.0.3