Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6 0 0 flow without stack #1448

Merged
merged 27 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
457d9f9
Initial
predic8 Dec 20, 2024
0e5ec37
Flow changed
predic8 Dec 20, 2024
d4e166f
Refactoring
predic8 Dec 20, 2024
6aa1906
Tests
predic8 Dec 20, 2024
021ee0a
Removed stack, refactoring
predic8 Dec 27, 2024
0a53be5
SOAP versioning example modernized, refactoring
predic8 Dec 28, 2024
fae531f
Fixed code issues
predic8 Dec 28, 2024
5bf6d60
Fixed internalProxyTest
predic8 Dec 28, 2024
565cfbb
Add SOAP Header example updated
predic8 Dec 28, 2024
c63c2e0
Updated StAX example
predic8 Dec 28, 2024
05adb45
Upate github build to 21
predic8 Dec 28, 2024
e7ab040
workflow_dispatch
predic8 Dec 28, 2024
eb5f125
Fixed tests, package scan form interceptors.* tests
predic8 Dec 30, 2024
1471296
Merge branch 'master' into 6-0-0-flow-without-stack
predic8 Dec 30, 2024
71f3ecc
Refactoring, Internal proxy started
predic8 Jan 1, 2025
70f519f
Merge remote-tracking branch 'origin/6-0-0-flow-without-stack' into 6…
predic8 Jan 1, 2025
35d9447
Refactoring, Internal proxy started
predic8 Jan 2, 2025
c55aef1
Refactoring tests, internal proxy tests
predic8 Jan 2, 2025
790c2e4
CodeQL update
predic8 Jan 2, 2025
c33d71f
CodeQL update Java 21
predic8 Jan 2, 2025
f758a63
LogInterceptor from headerOnly to body
predic8 Jan 3, 2025
a7440cd
Tests, refactoring
predic8 Jan 4, 2025
74968fe
Optimized example
predic8 Jan 4, 2025
5d0fb87
XPathCBR removed, test adjusted, examples, cleanup
predic8 Jan 4, 2025
09c905e
Error handling
predic8 Jan 5, 2025
d21d446
Refactoring
predic8 Jan 5, 2025
99280bd
Merge branch 'master' into 6-0-0-flow-without-stack
predic8 Jan 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Maven Build
run: |
Expand All @@ -23,10 +23,10 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Maven Build
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 17
java-version: 21
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
Expand All @@ -57,6 +57,6 @@ jobs:
rm -r core/src/test |
rm -r distribution/src/test
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ _*.swp
/core/.settings
/core/temp
/core/.DS_Store
core/src/test/resources/simplelogger.properties

# /maven-plugin
/maven-plugin/target
Expand All @@ -65,7 +66,7 @@ _*.swp
/distribution/membrane.log
/distribution/derby.log
/distribution/log.csv
/distribution/conf/proxies.xml
distribution/conf/proxies.xml
/distribution/examples/router/custom-interceptor/dist
/distribution/examples/router/loadbalancer-session-3/build
/distribution/examples/router/versioning/routing/build
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ A versatile and lightweight **API Gateway** for **REST** and **legacy SOAP Web S
- Advanced [load balancing](#load-balancing) to ensure high availability.
- Flexible [message transformation](#message-transformation) for seamless data processing.
- Embeddable reverse proxy HTTP framework to build custom API gateways.
- Traffic shadowing

# Content

Expand Down Expand Up @@ -69,10 +70,10 @@ A versatile and lightweight **API Gateway** for **REST** and **legacy SOAP Web S
9. [Traffic Control](#Traffic-Control) Rate limiting, Load balancing
- [Rate Limiting](#rate-limiting)
- [Load Balancing](#load-balancing)
8. [Legacy Web Services](#soap-web-services) SOAP and WSDL
10. [Legacy Web Services](#soap-web-services) SOAP and WSDL
- [API configuration from WSDL](#api-configuration-from-wsdl)
- [Message Validation against WSDL and XSD](#message-validation-against-wsdl-and-xsd)
9. [Operation](#Operation)
11. [Operation](#Operation)
- [Logging](#log-http)
- [Monitoring with Prometheus and Grafana](#monitoring-with-prometheus-and-grafana)
- [OpenTelemetry](#opentelemetry-integration)
Expand Down Expand Up @@ -263,7 +264,7 @@ For more routing options, see the [Membrane API documentation](https://www.membr

### Short Circuit

Sometimes, you may need an endpoint that doesn’t forward requests to a backend. Membrane makes it easy to create such endpoints.
Sometimes, you may need an endpoint that does not forward requests to a backend. Membrane makes it easy to create such endpoints.

#### Example: Health Check Endpoint
The following configuration creates a health check endpoint that responds to requests at [http://localhost:2000/health](http://localhost:2000/health):
Expand Down Expand Up @@ -604,19 +605,17 @@ This template will transform the JSON input into plain text:

### Transform XML into Text or JSON

Using the `xpathExtractor` you can extract values from XML request or response bodies and store it in properties. The properties are then available as variables in the `template`
Using `setProperty` you can extract values from XML request or response bodies and store it in properties. Then the properties are available as variables inside `template`.
plugin.

```xml

<api port="2000">
<request>
<xpathExtractor>
<property name="fn" xpath="person/@firstname"/>
</xpathExtractor>
<template>Buenas Noches, ${fn}sito!</template>
<setProperty name="fn" value="${/person/@firstname}" language="xpath"/>
<template>Buenas Noches, ${property.fn}sito!</template>
</request>
<return statusCode="200" contentType="text/plain"/>
<return/>
</api>
```

Expand Down
8 changes: 8 additions & 0 deletions annot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
117 changes: 49 additions & 68 deletions annot/src/main/java/com/predic8/membrane/annot/bean/MCUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,19 @@
limitations under the License. */
package com.predic8.membrane.annot.bean;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import com.predic8.membrane.annot.AnnotUtils;
import com.predic8.membrane.annot.MCAttribute;
import com.predic8.membrane.annot.MCChildElement;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.annot.MCOtherAttributes;
import com.predic8.membrane.annot.MCTextContent;
import com.predic8.membrane.annot.*;
import org.slf4j.*;
import org.springframework.beans.*;
import org.springframework.context.support.*;
import org.springframework.core.io.*;

import javax.xml.stream.*;
import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import java.util.*;

import static java.nio.charset.StandardCharsets.*;

/**
* A utility class to deeply-clone/serizalize/deserialize {@link MCElement}-annotatated objects
Expand All @@ -57,7 +39,9 @@
*/
public class MCUtil {

private static XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
private static final Logger log = LoggerFactory.getLogger(MCUtil.class.getName());

private static final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();

@SuppressWarnings("unchecked")
private static <T> T cloneInternal(T object, boolean deep) {
Expand All @@ -78,7 +62,7 @@ public static <T> T clone(T object, boolean deep) {
if (object == null)
throw new InvalidParameterException("'object' must not be null.");

Class<? extends Object> clazz = object.getClass();
Class<?> clazz = object.getClass();

MCElement e = clazz.getAnnotation(MCElement.class);
if (e == null)
Expand Down Expand Up @@ -130,6 +114,7 @@ public static <T> T fromXML(Class<T> clazz, final String xml) {
try {
fsxacApplicationContext.refresh();
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
System.err.println(xml);
throw e;
}
Expand Down Expand Up @@ -168,10 +153,9 @@ public Resource getResource(String location) {
if (MAGIC.equals(location)) {
return new FileSystemResource(MAGIC) {
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8")));
};

public InputStream getInputStream() {
return new ByteArrayInputStream(xml.getBytes(UTF_8));
}
};
}
return super.getResource(location);
Expand Down Expand Up @@ -213,7 +197,7 @@ private static void addXML(Object object, String id, XMLStreamWriter xew, Serial
if (object == null)
throw new InvalidParameterException("'object' must not be null.");

Class<? extends Object> clazz = object.getClass();
Class<?> clazz = object.getClass();

MCElement e = clazz.getAnnotation(MCElement.class);
if (e == null)
Expand All @@ -235,29 +219,27 @@ private static void addXML(Object object, String id, XMLStreamWriter xew, Serial
if (a != null) {
Object value = src.getPropertyValue(propertyName);
String str;
if (value == null)
continue;
else if (value instanceof String)
str = (String)value;
else if (value instanceof Boolean)
str = ((Boolean)value).toString();
else if (value instanceof Integer)
str = ((Integer)value).toString();
else if (value instanceof Long)
str = ((Long)value).toString();
else if (value instanceof Enum<?>)
str = value.toString();
else {
MCElement el = value.getClass().getAnnotation(MCElement.class);
if (el != null) {
str = defineBean(sc, value, null, true);
} else {
str = "?";
sc.incomplete = true;
}
}

if (a.attributeName().length() > 0)
switch (value) {
case null -> {
continue;
}
case String s -> str = s;
case Boolean b -> str = b.toString();
case Integer i -> str = i.toString();
case Long l -> str = l.toString();
case Enum<?> anEnum -> str = value.toString();
default -> {
MCElement el = value.getClass().getAnnotation(MCElement.class);
if (el != null) {
str = defineBean(sc, value, null, true);
} else {
str = "?";
sc.incomplete = true;
}
}
}

if (!a.attributeName().isEmpty())
propertyName = a.attributeName();

attributes.add(propertyName);
Expand All @@ -271,9 +253,8 @@ else if (value instanceof Enum<?>)
MCOtherAttributes o = m.getAnnotation(MCOtherAttributes.class);
if (o != null) {
Object value = src.getPropertyValue(propertyName);
if (value instanceof Map<?,?>) {
Map<?,?> map = (Map<?, ?>) value;
for (Map.Entry<?,?> entry : map.entrySet()) {
if (value instanceof Map<?, ?> map) {
for (Map.Entry<?,?> entry : map.entrySet()) {
Object key = entry.getKey();
Object val = entry.getValue();
if (!(key instanceof String) || !(val instanceof String)) {
Expand Down Expand Up @@ -308,8 +289,8 @@ else if (value instanceof Enum<?>)
Object value = src.getPropertyValue(propertyName);
if (value == null) {
continue;
} else if (value instanceof String) {
xew.writeCharacters((String)value);
} else if (value instanceof String v) {
xew.writeCharacters(v);
} else {
xew.writeCharacters("?");
sc.incomplete = true;
Expand All @@ -328,8 +309,8 @@ else if (value instanceof Enum<?>)

Object value = src.getPropertyValue(propertyName);
if (value != null) {
if (value instanceof Collection<?>) {
for (Object item : (Collection<?>)value)
if (value instanceof Collection<?> col) {
for (Object item : col)
addXML(item, null, xew, sc);
} else {
addXML(value, null, xew, sc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,16 @@
limitations under the License. */
package com.predic8.membrane.annot.generator.kubernetes;

import com.predic8.membrane.annot.model.MainInfo;
import com.predic8.membrane.annot.model.Model;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.tools.FileObject;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import com.predic8.membrane.annot.model.*;

import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.*;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.*;

import static java.util.stream.Stream.concat;
import static java.util.stream.Stream.*;

/**
* Autogenerates a helper file for JSON parsing
Expand Down Expand Up @@ -91,7 +87,7 @@ private void writeClassContent(Writer w, MainInfo mainInfo) throws IOException {
"",
"package " + mainInfo.getAnnotation().outputPackage() + ";",
"",
"import com.predic8.membrane.core.rules.Rule;",
"import com.predic8.membrane.core.proxies.Proxy;",
"import com.predic8.membrane.core.interceptor.Interceptor;",
"",
"import java.util.Map;",
Expand Down
20 changes: 8 additions & 12 deletions core/src/main/java/com/predic8/membrane/core/HttpRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@

package com.predic8.membrane.core;

import java.util.ArrayList;
import java.util.List;
import com.predic8.membrane.core.interceptor.*;
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.interceptor.DispatchingInterceptor;
import com.predic8.membrane.core.interceptor.HTTPClientInterceptor;
import com.predic8.membrane.core.interceptor.Interceptor;
import com.predic8.membrane.core.interceptor.RuleMatchingInterceptor;
import com.predic8.membrane.core.interceptor.UserFeatureInterceptor;
import com.predic8.membrane.core.transport.Transport;
import com.predic8.membrane.core.transport.http.HttpTransport;
import com.predic8.membrane.core.transport.http.client.ProxyConfiguration;
import java.util.*;

public class HttpRouter extends Router {

Expand All @@ -33,19 +28,20 @@ public HttpRouter() {
}

public HttpRouter(ProxyConfiguration proxyConfiguration) {
transport = createTransport(proxyConfiguration);
transport = createTransport();
resolverMap.getHTTPSchemaResolver().getHttpClientConfig().setProxy(proxyConfiguration);
}

/**
* Same as the default config from monitor-beans.xml
*/
private Transport createTransport(ProxyConfiguration proxyConfiguration) {
private Transport createTransport() {
Transport transport = new HttpTransport();
List<Interceptor> interceptors = new ArrayList<>();
interceptors.add(new RuleMatchingInterceptor());
interceptors.add(new DispatchingInterceptor());
interceptors.add(new UserFeatureInterceptor());
interceptors.add(new InternalServiceRoutingInterceptor());
HTTPClientInterceptor httpClientInterceptor = new HTTPClientInterceptor();
interceptors.add(httpClientInterceptor);
transport.setInterceptors(interceptors);
Expand Down
Loading
Loading