Skip to content

Commit

Permalink
Language improvements (#1482)
Browse files Browse the repository at this point in the history
* feat(interceptor): print plugin for logging messages

* feat(interceptor): print plugin for logging messages

* refactor(soap):

Fixed deprecation

* docs: roadmap

* test:  fixes

* refactor: language
feat: for plugin

* refactor: language

* refactor: language

* refactor: minor
  • Loading branch information
predic8 authored Jan 17, 2025
1 parent 29b669a commit 2b3bdeb
Show file tree
Hide file tree
Showing 28 changed files with 727 additions and 332 deletions.
2 changes: 2 additions & 0 deletions core/src/main/java/com/predic8/membrane/core/Router.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ public void start() {
""", e.getMessage(), e.getLocation());
System.exit(1);
} catch (Exception e) {
if (e instanceof RuntimeException)
throw (RuntimeException) e;
throw new RuntimeException(e);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,24 +161,9 @@ public void buildAndSetResponse(Exchange exchange) {
Map<String, Object> extensionsMap = new LinkedHashMap<>();

if (production) {
String logKey = UUID.randomUUID().toString();
log.warn("logKey={}\ntype={}\ntitle={}\n,detail={}\n,extension={},.", logKey, type, title, detail, extensionsMap);

type = "internal";
title = "An error occurred.";
detail = "Details can be found in the Membrane log searching for key: %s.".formatted(logKey);
logProduction(extensionsMap);
} else {
extensionsMap.putAll(extensions);
if (exception != null) {
if (extensionsMap.containsKey("message"))
log.error("Overriding ProblemDetails extensionsMap 'message' entry. Please notify Membrane developers.", new RuntimeException());
extensionsMap.put("message",exception.getMessage());
if (stacktrace) {
extensionsMap.put("stackTrace", getStackTrace());
}
}
extensionsMap.put("attention", """
Membrane is in development mode. For production set <router production="true"> to reduce details in error messages!""");
logDevelopment(extensionsMap);
}

root.put("title", title);
Expand All @@ -196,6 +181,32 @@ public void buildAndSetResponse(Exchange exchange) {
return root;
}

private void logDevelopment(Map<String, Object> extensionsMap) {
extensionsMap.putAll(extensions);
if (exception != null) {
if (extensionsMap.containsKey("message"))
log.error("Overriding ProblemDetails extensionsMap 'message' entry. Please notify Membrane developers.", new RuntimeException());
extensionsMap.put("message",exception.getMessage());
if (stacktrace) {
extensionsMap.put("stackTrace", getStackTrace());
}
}
extensionsMap.put("attention", """
Membrane is in development mode. For production set <router production="true"> to reduce details in error messages!""");
}

private void logProduction(Map<String, Object> extensionsMap) {
String logKey = UUID.randomUUID().toString();
log.warn("logKey={}\ntype={}\ntitle={}\n,detail={}\n,extension={},.", logKey, type, title, detail, extensionsMap);

type = "internal";
title = "An error occurred.";
detail = "Details can be found in the Membrane log searching for key: %s.".formatted(logKey);
if (stacktrace) {
log.warn("",exception);
}
}

private @NotNull Map getStackTrace() {
var m = new LinkedHashMap<>();
for (int i = 0; i < exception.getStackTrace().length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public class SpringConfigurationErrorHandler {
public static final String STARS = "**********************************************************************************";

public static void handleRootCause(Exception e, Logger log) {

ConfigurationException ce = checkForConfigurationException(e);
if (ce != null) {
handleConfigurationException(ce);
return;
}

switch (ExceptionUtils.getRootCause(e)) {
case PropertyBatchUpdateException pbue -> handlePropertyBatchUpdateException(log, pbue);
case ConfigurationException ee -> handleConfigurationException(ee);
Expand All @@ -41,6 +48,15 @@ public static void handleRootCause(Exception e, Logger log) {
}
}

private static ConfigurationException checkForConfigurationException(Exception e) {
for (Throwable t : ExceptionUtils.getThrowableList(e)) {
if (t instanceof ConfigurationException ce) {
return ce;
}
}
return null;
}

private static void handlePortOccupiedException(PortOccupiedException poe) {
if (poe.getPort() < 1024) {
System.err.printf("""
Expand Down Expand Up @@ -109,18 +125,18 @@ private static String getHowToFindPortWindows() {
private static void handleConfigurationException(ConfigurationException ce) {
var reason = "";
if (ce.getCause() != null) {
reason = "\nReason: " + ce.getCause().getMessage();
reason = "\nReason: %s\n".formatted(ce.getCause().getMessage());
}
System.err.printf("""
************** Configuration Error ***********************************
%s
%s
%s%s
Giving up.
Check proxies.xml file for errors.
%n""", ce.getMessage(),reason);
%n""", ce.getMessage());
}

@SuppressWarnings("StringConcatenationInLoop")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.*;

import static com.predic8.membrane.core.http.Header.*;
import static com.predic8.membrane.core.interceptor.Interceptor.Flow.REQUEST;
import static com.predic8.membrane.core.interceptor.Outcome.ABORT;
import static com.predic8.membrane.core.interceptor.Outcome.*;

Expand All @@ -35,8 +36,6 @@ public class CallInterceptor extends AbstractExchangeExpressionInterceptor {

private static HTTPClientInterceptor hcInterceptor;

private String url;

/**
* These headers are filtered out from the response of a called resource
* and are not added to the current message.
Expand All @@ -54,12 +53,12 @@ public void init() {

@Override
public Outcome handleRequest(Exchange exc) {
return handleInternal(exc);
return handleInternal(exc);
}

@Override
public Outcome handleResponse(Exchange exc) {
return handleInternal(exc);
return handleInternal(exc);
}

private Outcome handleInternal(Exchange exc) {
Expand All @@ -70,13 +69,11 @@ private Outcome handleInternal(Exchange exc) {
}

private @NotNull Outcome doCall(Exchange exc) {
if (url != null) {
try {
exc.setDestinations(List.of(exchangeExpression.evaluate(exc, Flow.REQUEST, String.class)));
} catch (ExchangeExpressionException e) {
e.provideDetails(ProblemDetails.internal(getRouter().isProduction())).buildAndSetResponse(exc);
return ABORT;
}
try {
exc.setDestinations(List.of(exchangeExpression.evaluate(exc, REQUEST, String.class)));
} catch (ExchangeExpressionException e) {
e.provideDetails(ProblemDetails.internal(getRouter().isProduction())).buildAndSetResponse(exc);
return ABORT;
}
log.debug("Calling {}", exc.getDestinations());
try {
Expand All @@ -88,7 +85,7 @@ private Outcome handleInternal(Exchange exc) {
exc.getRequest().setBodyContent(exc.getResponse().getBody().getContent()); // TODO Optimize?
copyHeadersFromResponseToRequest(exc);
exc.getRequest().getHeader().setContentType(exc.getResponse().getHeader().getContentType());
log.debug("Outcome of call {}",outcome);
log.debug("Outcome of call {}", outcome);
return CONTINUE;
} catch (Exception e) {
ProblemDetails.internal(router.isProduction())
Expand Down Expand Up @@ -117,11 +114,11 @@ static void copyHeadersFromResponseToRequest(Exchange exc) {
@MCAttribute
@Required
public void setUrl(String url) {
this.url = url;
this.expression = url;
}

public String getUrl() {
return url;
return expression;
}

@Override
Expand All @@ -131,6 +128,6 @@ public String getDisplayName() {

@Override
public String getShortDescription() {
return "Calls %s".formatted(url);
return "Calls %s".formatted(expression);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* 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.interceptor.flow;

import com.predic8.membrane.annot.*;
import com.predic8.membrane.core.exceptions.*;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.interceptor.*;
import com.predic8.membrane.core.lang.*;
import com.predic8.membrane.core.lang.ExchangeExpression.*;
import com.predic8.membrane.core.util.*;
import org.slf4j.*;

import java.util.*;

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.ABORT;
import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE;
import static com.predic8.membrane.core.lang.ExchangeExpression.Language.SPEL;

@MCElement(name = "for")
public class ForInterceptor extends AbstractFlowInterceptor {

private static final Logger log = LoggerFactory.getLogger(ForInterceptor.class);

private String in;
private Language language = SPEL;

private ExchangeExpression exchangeExpression;

@Override
public void init() {
super.init();
try {
exchangeExpression = ExchangeExpression.getInstance(router, language, in);
} catch (ConfigurationException ce) {
throw new ConfigurationException(ce.getMessage() + """
<for in="%s">""".formatted(in), ce.getCause());
}
}

@Override
public Outcome handleRequest(Exchange exc) {
return handleInternal(exc, REQUEST);
}

@Override
public Outcome handleResponse(Exchange exc) {
return handleInternal(exc, RESPONSE);
}

private Outcome handleInternal(Exchange exc, Flow flow) {
Object o;
try {
o = exchangeExpression.evaluate(exc, flow, Object.class);
} catch (ExchangeExpressionException e) {
e.provideDetails(ProblemDetails.internal(router.isProduction()))
.detail("Error evaluating expression on exchange.")
.component(getDisplayName())
.buildAndSetResponse(exc);
return ABORT;
}

if (o instanceof List<?> l) {
log.debug("List detected {}",l);
for (Object o2 : l) {
log.debug("type: {}, it: {}",o2.getClass(),o2);
if (flow.isRequest()) {
exc.setProperty("it", o2);
getFlowController().invokeRequestHandlers(exc, interceptors);
}
}
}

return CONTINUE;
}

public Language getLanguage() {
return language;
}

/**
* @description the language of the 'test' condition
* @default groovy
* @example SpEL, groovy, jsonpath, xpath
*/
@MCAttribute
public void setLanguage(Language language) {
this.language = language;
}

public String getIn() {
return in;
}

/**
*
*/
@Required
@MCAttribute
public void setIn(String in) {
this.in = in;
}

@Override
public String getDisplayName() {
return "for";
}

@Override
public String getShortDescription() {
StringBuilder ret = new StringBuilder("for (" + in + ") {");
for (Interceptor i : getInterceptors()) {
ret.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;").append(i.getDisplayName());
}
ret.append("<br/>}");
return ret.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private Outcome handleInternal(Exchange exc, Flow flow) {
result = exchangeExpression.evaluate(exc, flow, Boolean.class);
} catch (ExchangeExpressionException e) {
e.provideDetails(ProblemDetails.internal(router.isProduction()))
.detail("Error evaluating expression on exchange in if plugin.")
.detail("Error evaluating expression on exchange.")
.component("if")
.buildAndSetResponse(exc);
return ABORT;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
/* 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.interceptor.lang;

import com.predic8.membrane.core.lang.*;

public class AbstractExchangeExpressionInterceptor extends AbstractLanguageInterceptor {

protected ExchangeExpression exchangeExpression;
protected String expression = ""; // default if there is no expression

@Override
public void init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ abstract class AbstractLanguageInterceptor extends AbstractInterceptor {
*/
protected Language language = SPEL;

protected String expression = ""; // default if there is no expression

public Language getLanguage() {
return language;
}
Expand Down
Loading

0 comments on commit 2b3bdeb

Please sign in to comment.