mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
test: add dubbo integration-test
This commit is contained in:
@@ -9,6 +9,7 @@ on:
|
||||
- './github/workflows/memshell-integration-test.yml'
|
||||
- '**/memshell/**'
|
||||
- '**/packer/**'
|
||||
- '**/dubbo/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
@@ -54,6 +55,8 @@ jobs:
|
||||
depend_tasks: ""
|
||||
- middleware: "geronimo"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "dubbo"
|
||||
depend_tasks: ":vul:vul-dubbo:dubboProviderFatJars :tools:command:dubboClientClasspath"
|
||||
runs-on: ubuntu-22.04
|
||||
name: ${{ matrix.cases.middleware }}
|
||||
steps:
|
||||
@@ -73,10 +76,15 @@ jobs:
|
||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||
|
||||
- name: Integration Test with gradle
|
||||
if: matrix.cases.middleware != 'dubbo'
|
||||
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||
|
||||
- name: Dubbo Integration Test with gradle
|
||||
if: matrix.cases.middleware == 'dubbo'
|
||||
run: ./gradlew :integration-test:dubboContainerTest --info
|
||||
|
||||
- name: Export Integration Test Summary
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
if: success() || failure()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
report_paths: '**/build/test-results/*/TEST-*.xml'
|
||||
|
||||
@@ -7,6 +7,9 @@ plugins {
|
||||
group = "io.github.reajason"
|
||||
version = rootProject.version
|
||||
|
||||
evaluationDependsOn(":vul:vul-dubbo")
|
||||
evaluationDependsOn(":tools:command")
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs.add(file("src/main"))
|
||||
@@ -36,8 +39,41 @@ dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
val dubboProviderProject = project(":vul:vul-dubbo")
|
||||
val dubboCommandProject = project(":tools:command")
|
||||
|
||||
fun dubboProviderJar(taskName: String): Provider<String> {
|
||||
return dubboProviderProject.tasks.named<Jar>(taskName).flatMap { task ->
|
||||
task.archiveFile.map { it.asFile.absolutePath }
|
||||
}
|
||||
}
|
||||
|
||||
fun dubboClientClasspath(clientKind: String): Provider<String> {
|
||||
return dubboCommandProject.layout.buildDirectory.file("dubbo-client-classpaths/$clientKind.txt").map {
|
||||
it.asFile.readText()
|
||||
}
|
||||
}
|
||||
|
||||
fun Test.configureDubboSystemProperties() {
|
||||
dependsOn(":vul:vul-dubbo:dubboProviderFatJars", ":tools:command:dubboClientClasspath")
|
||||
val systemProperties = mapOf(
|
||||
"dubbo.alibaba.client.classpath" to dubboClientClasspath("alibaba"),
|
||||
"dubbo.apache.client.classpath" to dubboClientClasspath("apache"),
|
||||
"dubbo.alibaba.provider.jar" to dubboProviderJar("dubboAlibabaProviderFatJar"),
|
||||
"dubbo.apache276.provider.jar" to dubboProviderJar("dubboApache276ProviderFatJar"),
|
||||
"dubbo.apache277.provider.jar" to dubboProviderJar("dubboApache277ProviderFatJar"),
|
||||
"dubbo.apache278.provider.jar" to dubboProviderJar("dubboApache278ProviderFatJar"),
|
||||
"dubbo.apache2723.provider.jar" to dubboProviderJar("dubboApache2723ProviderFatJar"),
|
||||
"dubbo.apache336.provider.jar" to dubboProviderJar("dubboApache336ProviderFatJar")
|
||||
)
|
||||
doFirst {
|
||||
systemProperties.forEach { (key, value) ->
|
||||
systemProperty(key, value.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Test.configureIntegrationJvm() {
|
||||
jvmArgs(
|
||||
"--add-opens=java.base/java.util=ALL-UNNAMED",
|
||||
"--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED",
|
||||
@@ -47,3 +83,23 @@ tasks.test {
|
||||
events("passed", "skipped", "failed")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform {
|
||||
excludeTags("dubbo-container")
|
||||
}
|
||||
configureIntegrationJvm()
|
||||
}
|
||||
|
||||
tasks.register<Test>("dubboContainerTest") {
|
||||
group = "verification"
|
||||
description = "Runs DubboService provider/client integration tests."
|
||||
testClassesDirs = sourceSets.test.get().output.classesDirs
|
||||
classpath = sourceSets.test.get().runtimeClasspath
|
||||
useJUnitPlatform {
|
||||
includeTags("dubbo-container")
|
||||
}
|
||||
dependsOn("testClasses")
|
||||
configureDubboSystemProperties()
|
||||
configureIntegrationJvm()
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Testcontainers
|
||||
@Tag("dubbo-container")
|
||||
class AlibabaDubbo2612ContainerTest {
|
||||
|
||||
private static final DubboProviderScenario SCENARIO = new DubboProviderScenario(
|
||||
"alibaba-dubbo-2.6.12",
|
||||
"alibaba",
|
||||
"dubbo.alibaba.provider.jar",
|
||||
"eclipse-temurin:8-jre",
|
||||
20880,
|
||||
Opcodes.V1_8,
|
||||
List.of(
|
||||
new DubboProtocolTarget("dubbo", 20880),
|
||||
new DubboProtocolTarget("hessian", 28080)
|
||||
)
|
||||
);
|
||||
|
||||
@Container
|
||||
static final GenericContainer<?> container = DubboContainerFactory.buildProvider(SCENARIO);
|
||||
|
||||
@Test
|
||||
void testDubboServiceRegistration() {
|
||||
DubboServiceAssertion.assertCommandService(container, SCENARIO);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Testcontainers
|
||||
@Tag("dubbo-container")
|
||||
class ApacheDubbo27xContainerTest {
|
||||
|
||||
private static final String IMAGE = "eclipse-temurin:17-jdk";
|
||||
|
||||
private static final DubboProviderScenario APACHE_276 = apacheScenario(
|
||||
"apache-dubbo-2.7.6",
|
||||
"dubbo.apache276.provider.jar",
|
||||
20885,
|
||||
28086
|
||||
);
|
||||
private static final DubboProviderScenario APACHE_277 = apacheScenario(
|
||||
"apache-dubbo-2.7.7",
|
||||
"dubbo.apache277.provider.jar",
|
||||
20886,
|
||||
28088
|
||||
);
|
||||
private static final DubboProviderScenario APACHE_278 = apacheScenario(
|
||||
"apache-dubbo-2.7.8",
|
||||
"dubbo.apache278.provider.jar",
|
||||
20887,
|
||||
28090
|
||||
);
|
||||
private static final DubboProviderScenario APACHE_2723 = apacheScenario(
|
||||
"apache-dubbo-2.7.23",
|
||||
"dubbo.apache2723.provider.jar",
|
||||
20881,
|
||||
28082
|
||||
);
|
||||
|
||||
@Container
|
||||
static final GenericContainer<?> apache276 = DubboContainerFactory.buildProvider(APACHE_276);
|
||||
@Container
|
||||
static final GenericContainer<?> apache277 = DubboContainerFactory.buildProvider(APACHE_277);
|
||||
@Container
|
||||
static final GenericContainer<?> apache278 = DubboContainerFactory.buildProvider(APACHE_278);
|
||||
@Container
|
||||
static final GenericContainer<?> apache2723 = DubboContainerFactory.buildProvider(APACHE_2723);
|
||||
|
||||
static Stream<Arguments> scenarios() {
|
||||
return Stream.of(
|
||||
Arguments.of(apache276, APACHE_276),
|
||||
Arguments.of(apache277, APACHE_277),
|
||||
Arguments.of(apache278, APACHE_278),
|
||||
Arguments.of(apache2723, APACHE_2723)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{1}")
|
||||
@MethodSource("scenarios")
|
||||
void testDubboServiceRegistration(GenericContainer<?> container, DubboProviderScenario scenario) {
|
||||
DubboServiceAssertion.assertCommandService(container, scenario);
|
||||
}
|
||||
|
||||
private static DubboProviderScenario apacheScenario(String name, String providerJarProperty, int dubboPort, int hessianPort) {
|
||||
return new DubboProviderScenario(
|
||||
name,
|
||||
"apache",
|
||||
providerJarProperty,
|
||||
IMAGE,
|
||||
dubboPort,
|
||||
Opcodes.V1_8,
|
||||
List.of(
|
||||
new DubboProtocolTarget("dubbo", dubboPort),
|
||||
new DubboProtocolTarget("hessian", hessianPort)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Testcontainers
|
||||
@Tag("dubbo-container")
|
||||
class ApacheDubbo336ContainerTest {
|
||||
|
||||
private static final DubboProviderScenario SCENARIO = new DubboProviderScenario(
|
||||
"apache-dubbo-3.3.6",
|
||||
"apache",
|
||||
"dubbo.apache336.provider.jar",
|
||||
"eclipse-temurin:17-jdk",
|
||||
20882,
|
||||
Opcodes.V1_8,
|
||||
List.of(
|
||||
new DubboProtocolTarget("dubbo", 20882),
|
||||
new DubboProtocolTarget("hessian", 28084),
|
||||
new DubboProtocolTarget("tri", 50051)
|
||||
)
|
||||
);
|
||||
|
||||
@Container
|
||||
static final GenericContainer<?> container = DubboContainerFactory.buildProvider(SCENARIO);
|
||||
|
||||
@Test
|
||||
void testDubboServiceRegistration() {
|
||||
DubboServiceAssertion.assertCommandService(container, SCENARIO);
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
final class DubboClientRunner {
|
||||
|
||||
private DubboClientRunner() {
|
||||
}
|
||||
|
||||
static String loadBytes(String clientKind, String url, String base64) {
|
||||
return run(clientKind, "load-bytes", url, base64);
|
||||
}
|
||||
|
||||
static String runCommand(String clientKind, String url, String interfaceName, String command) {
|
||||
return run(clientKind, "run-command", url, interfaceName, command);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static String run(String clientKind, String... args) {
|
||||
List<String> command = new ArrayList<String>();
|
||||
String javaExecutable = javaExecutable(clientKind);
|
||||
command.add(javaExecutable);
|
||||
if (supportsAddOpens(javaExecutable)) {
|
||||
command.add("--add-opens=java.base/java.lang=ALL-UNNAMED");
|
||||
command.add("--add-opens=java.base/java.math=ALL-UNNAMED");
|
||||
}
|
||||
command.add("-cp");
|
||||
command.add(clientClasspath(clientKind));
|
||||
command.add(mainClass(clientKind));
|
||||
for (String arg : args) {
|
||||
command.add(arg);
|
||||
}
|
||||
|
||||
Process process = new ProcessBuilder(command)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy(process.getInputStream(), output);
|
||||
int exitCode = process.waitFor();
|
||||
String rendered = output.toString(StandardCharsets.UTF_8).trim();
|
||||
if (exitCode != 0) {
|
||||
throw new IllegalStateException("Dubbo client failed with exit code " + exitCode + "\n" + rendered);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
private static String clientClasspath(String clientKind) {
|
||||
String property = System.getProperty("dubbo." + clientKind + ".client.classpath");
|
||||
if (isBlank(property)) {
|
||||
throw new IllegalStateException("missing dubbo." + clientKind + ".client.classpath system property");
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
private static String mainClass(String clientKind) {
|
||||
if ("alibaba".equals(clientKind)) {
|
||||
return "io.github.reajason.dubbo.fixture.client.alibaba.AlibabaDubboClient";
|
||||
}
|
||||
if ("apache".equals(clientKind)) {
|
||||
return "io.github.reajason.dubbo.fixture.client.apache.ApacheDubboClient";
|
||||
}
|
||||
throw new IllegalArgumentException("unsupported client kind: " + clientKind);
|
||||
}
|
||||
|
||||
private static String javaExecutable(String clientKind) {
|
||||
if (!"alibaba".equals(clientKind)) {
|
||||
return "java";
|
||||
}
|
||||
String java8Home = System.getenv("JAVA8_HOME");
|
||||
if (isBlank(java8Home)) {
|
||||
java8Home = System.getProperty("java8.home");
|
||||
}
|
||||
if (isBlank(java8Home)) {
|
||||
return "java";
|
||||
}
|
||||
return java8Home + "/bin/java";
|
||||
}
|
||||
|
||||
private static boolean supportsAddOpens(String javaExecutable) throws java.io.IOException, InterruptedException {
|
||||
Process process = new ProcessBuilder(javaExecutable, "-version")
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy(process.getInputStream(), output);
|
||||
int exitCode = process.waitFor();
|
||||
if (exitCode != 0) {
|
||||
return true;
|
||||
}
|
||||
return majorVersion(output.toString(StandardCharsets.UTF_8)) >= 9;
|
||||
}
|
||||
|
||||
private static int majorVersion(String versionOutput) {
|
||||
Matcher matcher = Pattern.compile("version \"([^\"]+)\"").matcher(versionOutput);
|
||||
if (!matcher.find()) {
|
||||
return 9;
|
||||
}
|
||||
String version = matcher.group(1);
|
||||
if (version.startsWith("1.")) {
|
||||
int dot = version.indexOf('.', 2);
|
||||
return leadingInteger(dot < 0 ? version.substring(2) : version.substring(2, dot));
|
||||
}
|
||||
int dot = version.indexOf('.');
|
||||
return leadingInteger(dot < 0 ? version : version.substring(0, dot));
|
||||
}
|
||||
|
||||
private static int leadingInteger(String value) {
|
||||
Matcher matcher = Pattern.compile("^(\\d+)").matcher(value);
|
||||
return matcher.find() ? Integer.parseInt(matcher.group(1)) : 9;
|
||||
}
|
||||
|
||||
private static boolean isBlank(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
|
||||
private static void copy(InputStream inputStream, ByteArrayOutputStream outputStream) throws java.io.IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
while ((read = inputStream.read(buffer)) >= 0) {
|
||||
outputStream.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.utility.MountableFile;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
|
||||
final class DubboContainerFactory {
|
||||
|
||||
private DubboContainerFactory() {
|
||||
}
|
||||
|
||||
static GenericContainer<?> buildProvider(DubboProviderScenario scenario) {
|
||||
String jarPath = providerJarPath(scenario.providerJarProperty());
|
||||
GenericContainer<?> container = new GenericContainer<>(scenario.imageName())
|
||||
.withCopyFileToContainer(MountableFile.forHostPath(jarPath), "/app/app.jar")
|
||||
.withWorkingDirectory("/app")
|
||||
.withExposedPorts(exposedPorts(scenario))
|
||||
.waitingFor(Wait.forLogMessage(".*Provider started.*", 1)
|
||||
.withStartupTimeout(Duration.ofMinutes(3)));
|
||||
|
||||
if ("alibaba".equals(scenario.clientKind())) {
|
||||
container.withCommand("java", "-jar", "/app/app.jar");
|
||||
} else {
|
||||
container.withCommand(
|
||||
"java",
|
||||
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
|
||||
"--add-opens", "java.base/java.math=ALL-UNNAMED",
|
||||
"-jar", "/app/app.jar"
|
||||
);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
private static Integer[] exposedPorts(DubboProviderScenario scenario) {
|
||||
return scenario.commandTargets().stream()
|
||||
.map(DubboProtocolTarget::port)
|
||||
.distinct()
|
||||
.toArray(Integer[]::new);
|
||||
}
|
||||
|
||||
private static String providerJarPath(String propertyName) {
|
||||
String value = System.getProperty(propertyName);
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
throw new IllegalStateException("missing " + propertyName + " system property");
|
||||
}
|
||||
Path path = Path.of(value);
|
||||
if (!Files.isRegularFile(path)) {
|
||||
throw new IllegalStateException("provider jar does not exist: " + path);
|
||||
}
|
||||
return path.toAbsolutePath().toString();
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
final class DubboProtocolTarget {
|
||||
private final String protocol;
|
||||
private final int port;
|
||||
|
||||
DubboProtocolTarget(String protocol, int port) {
|
||||
this.protocol = protocol;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
String protocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
String url(String host, String interfaceName) {
|
||||
return protocol + "://" + host + ":" + port + "/" + interfaceName;
|
||||
}
|
||||
|
||||
String url(String host, int mappedPort, String interfaceName) {
|
||||
return protocol + "://" + host + ":" + mappedPort + "/" + interfaceName;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class DubboProviderScenario {
|
||||
private final String name;
|
||||
private final String clientKind;
|
||||
private final String providerJarProperty;
|
||||
private final String imageName;
|
||||
private final int loaderPort;
|
||||
private final int targetJdkVersion;
|
||||
private final List<DubboProtocolTarget> commandTargets;
|
||||
|
||||
DubboProviderScenario(String name, String clientKind, String providerJarProperty, String imageName,
|
||||
int loaderPort, int targetJdkVersion, List<DubboProtocolTarget> commandTargets) {
|
||||
this.name = name;
|
||||
this.clientKind = clientKind;
|
||||
this.providerJarProperty = providerJarProperty;
|
||||
this.imageName = imageName;
|
||||
this.loaderPort = loaderPort;
|
||||
this.targetJdkVersion = targetJdkVersion;
|
||||
this.commandTargets = commandTargets;
|
||||
}
|
||||
|
||||
String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
String clientKind() {
|
||||
return clientKind;
|
||||
}
|
||||
|
||||
String providerJarProperty() {
|
||||
return providerJarProperty;
|
||||
}
|
||||
|
||||
String imageName() {
|
||||
return imageName;
|
||||
}
|
||||
|
||||
int loaderPort() {
|
||||
return loaderPort;
|
||||
}
|
||||
|
||||
int targetJdkVersion() {
|
||||
return targetJdkVersion;
|
||||
}
|
||||
|
||||
List<DubboProtocolTarget> commandTargets() {
|
||||
return commandTargets;
|
||||
}
|
||||
|
||||
String shellType() {
|
||||
if ("alibaba".equals(clientKind)) {
|
||||
return ShellType.ALIBABA_DUBBO_SERVICE;
|
||||
}
|
||||
return ShellType.APACHE_DUBBO_SERVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
@Slf4j
|
||||
final class DubboServiceAssertion {
|
||||
|
||||
private static final String LOADER_INTERFACE = "io.github.reajason.dubbo.fixture.api.BytecodeLoadingService";
|
||||
private static final String COMMAND = "id";
|
||||
|
||||
private DubboServiceAssertion() {
|
||||
}
|
||||
|
||||
static void assertCommandService(GenericContainer<?> container, DubboProviderScenario scenario) {
|
||||
ShellToolConfig shellToolConfig = ShellAssertion.getShellToolConfig(
|
||||
scenario.shellType(),
|
||||
ShellTool.Command,
|
||||
Packers.Base64
|
||||
);
|
||||
MemShellResult result = ShellAssertion.generate(
|
||||
null,
|
||||
Server.Dubbo,
|
||||
null,
|
||||
scenario.shellType(),
|
||||
ShellTool.Command,
|
||||
scenario.targetJdkVersion(),
|
||||
shellToolConfig,
|
||||
Packers.Base64
|
||||
);
|
||||
String interfaceName = result.getInjectorConfig().getUrlPattern();
|
||||
String host = container.getHost();
|
||||
String loaderUrl = "dubbo://" + host + ":" + container.getMappedPort(scenario.loaderPort()) + "/" + LOADER_INTERFACE;
|
||||
|
||||
log.info("loading {} into {} via {}", interfaceName, scenario.name(), loaderUrl);
|
||||
String loadOutput = DubboClientRunner.loadBytes(scenario.clientKind(), loaderUrl, result.getInjectorBytesBase64Str());
|
||||
log.info("{} load output: {}", scenario.name(), loadOutput);
|
||||
|
||||
List<String> fallbackUrls = scenario.commandTargets().stream()
|
||||
.map(target -> target.url(host, container.getMappedPort(target.port()), interfaceName))
|
||||
.collect(Collectors.toList());
|
||||
List<String> commandUrls = DubboUrlResolver.resolveCommandUrls(loadOutput, interfaceName, fallbackUrls);
|
||||
|
||||
for (String commandUrl : commandUrls) {
|
||||
String output = DubboClientRunner.runCommand(scenario.clientKind(), commandUrl, interfaceName, COMMAND);
|
||||
log.info("{} {} command output: {}", scenario.name(), DubboUrlResolver.protocolOf(commandUrl), output);
|
||||
assertThat(output, anyOf(containsString("uid="), containsString("injected-ok")));
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final class DubboUrlResolver {
|
||||
|
||||
private DubboUrlResolver() {
|
||||
}
|
||||
|
||||
static List<String> resolveCommandUrls(String loadOutput, String interfaceName, List<String> fallbackUrls) {
|
||||
Map<String, String> discoveredByProtocol = new LinkedHashMap<String, String>();
|
||||
Pattern pattern = Pattern.compile("(dubbo|hessian|tri)://[^\\s,]*" + Pattern.quote(interfaceName) + "(?:\\?[^\\s,]*)?");
|
||||
Matcher matcher = pattern.matcher(loadOutput);
|
||||
while (matcher.find()) {
|
||||
String candidate = matcher.group();
|
||||
discoveredByProtocol.put(protocolOf(candidate), candidate);
|
||||
}
|
||||
return fallbackUrls.stream()
|
||||
.map(fallback -> {
|
||||
String discovered = discoveredByProtocol.get(protocolOf(fallback));
|
||||
return discovered == null ? fallback : rewriteEndpoint(discovered, fallback);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static String protocolOf(String url) {
|
||||
int separator = url.indexOf("://");
|
||||
return separator < 0 ? url : url.substring(0, separator);
|
||||
}
|
||||
|
||||
static String rewriteHost(String url, String host) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
return new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
host,
|
||||
uri.getPort(),
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment()
|
||||
).toString();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException("invalid direct url: " + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
static String rewriteEndpoint(String url, String endpointUrl) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
URI endpoint = new URI(endpointUrl);
|
||||
return new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
endpoint.getHost(),
|
||||
endpoint.getPort(),
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment()
|
||||
).toString();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException("invalid direct url: " + url + " or " + endpointUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.reajason.javaweb.integration.memshell.dubbo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
|
||||
class DubboUrlResolverTest {
|
||||
|
||||
@Test
|
||||
void discoveredUrlsOverrideFallbackByProtocolAndRewriteHost() {
|
||||
String interfaceName = "org.example.ICommandService";
|
||||
String loadOutput = "ok dubbo://x.x.x.x:20880/" + interfaceName + "?side=provider, "
|
||||
+ "hessian://10.1.2.3:28080/" + interfaceName;
|
||||
|
||||
List<String> resolved = DubboUrlResolver.resolveCommandUrls(
|
||||
loadOutput,
|
||||
interfaceName,
|
||||
List.of(
|
||||
"dubbo://127.0.0.1:1111/" + interfaceName,
|
||||
"hessian://127.0.0.1:2222/" + interfaceName,
|
||||
"tri://127.0.0.1:3333/" + interfaceName
|
||||
)
|
||||
);
|
||||
|
||||
assertThat(resolved, contains(
|
||||
"dubbo://127.0.0.1:1111/" + interfaceName + "?side=provider",
|
||||
"hessian://127.0.0.1:2222/" + interfaceName,
|
||||
"tri://127.0.0.1:3333/" + interfaceName
|
||||
));
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -28,7 +28,7 @@ dependencyResolutionManagement {
|
||||
rootProject.name = "memshell-party"
|
||||
|
||||
include("memshell-party-common")
|
||||
include("tools:godzilla", "tools:behinder", "tools:suo5", "tools:ant-sword")
|
||||
include("tools:godzilla", "tools:behinder", "tools:suo5", "tools:ant-sword", "tools:command")
|
||||
include("packer")
|
||||
include("boot")
|
||||
include("generator")
|
||||
@@ -47,6 +47,7 @@ include("vul:vul-springboot359")
|
||||
include("vul:vul-springboot2-webflux")
|
||||
include("vul:vul-springboot3-webflux")
|
||||
include("vul:vul-playframework")
|
||||
include("vul:vul-dubbo")
|
||||
include("memshell-agent:memshell-agent-attacher")
|
||||
include("memshell-agent:memshell-agent-asm")
|
||||
include("memshell-agent:memshell-agent-javassist")
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("idea")
|
||||
}
|
||||
|
||||
group = "io.github.reajason"
|
||||
version = rootProject.version
|
||||
|
||||
val dubboClientCommon: SourceSet by sourceSets.creating
|
||||
val dubboClientAlibaba: SourceSet by sourceSets.creating
|
||||
val dubboClientApache: SourceSet by sourceSets.creating
|
||||
|
||||
val dubboClientCommonImplementation: Configuration by configurations.getting
|
||||
val dubboClientAlibabaImplementation: Configuration by configurations.getting
|
||||
val dubboClientApacheImplementation: Configuration by configurations.getting
|
||||
|
||||
val dubboClientCommonOutput = dubboClientCommon.output
|
||||
|
||||
dubboClientAlibaba.compileClasspath += dubboClientCommonOutput
|
||||
dubboClientAlibaba.runtimeClasspath += dubboClientCommonOutput
|
||||
dubboClientApache.compileClasspath += dubboClientCommonOutput
|
||||
dubboClientApache.runtimeClasspath += dubboClientCommonOutput
|
||||
|
||||
listOf(
|
||||
"dubboClientApacheCompileClasspath",
|
||||
"dubboClientApacheRuntimeClasspath"
|
||||
).forEach { configurationName ->
|
||||
configurations.named(configurationName) {
|
||||
exclude(group = "io.netty", module = "netty-transport-native-kqueue")
|
||||
exclude(group = "io.netty", module = "netty-resolver-dns-native-macos")
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs.add(file("src/main"))
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dubboClientCommonImplementation("org.slf4j:slf4j-api:1.7.36")
|
||||
|
||||
dubboClientAlibabaImplementation(dubboClientCommonOutput)
|
||||
dubboClientAlibabaImplementation("com.alibaba:dubbo:2.6.12")
|
||||
dubboClientAlibabaImplementation("com.alibaba:hessian-lite:3.2.4")
|
||||
dubboClientAlibabaImplementation("com.caucho:hessian:4.0.51")
|
||||
dubboClientAlibabaImplementation("org.apache.httpcomponents:httpclient:4.5.3")
|
||||
dubboClientAlibabaImplementation("org.springframework:spring-web:5.3.39")
|
||||
dubboClientAlibabaImplementation("io.netty:netty-all:4.1.25.Final")
|
||||
dubboClientAlibabaImplementation("org.mortbay.jetty:jetty:6.1.26")
|
||||
dubboClientAlibabaImplementation("org.mortbay.jetty:jetty-util:6.1.26")
|
||||
dubboClientAlibabaImplementation("org.slf4j:slf4j-api:1.7.36")
|
||||
dubboClientAlibabaImplementation("ch.qos.logback:logback-classic:1.2.13")
|
||||
|
||||
dubboClientApacheImplementation(dubboClientCommonOutput)
|
||||
dubboClientApacheImplementation("org.apache.dubbo:dubbo:3.3.6") {
|
||||
exclude(group = "log4j", module = "log4j")
|
||||
}
|
||||
dubboClientApacheImplementation("org.apache.dubbo:dubbo-rpc-triple:3.3.6")
|
||||
dubboClientApacheImplementation("org.apache.dubbo.extensions:dubbo-rpc-http:3.3.1")
|
||||
dubboClientApacheImplementation("org.apache.dubbo.extensions:dubbo-rpc-hessian:3.3.0")
|
||||
dubboClientApacheImplementation("org.apache.dubbo:dubbo-remoting-http:3.3.0-beta.2")
|
||||
dubboClientApacheImplementation("com.caucho:hessian:4.0.51")
|
||||
dubboClientApacheImplementation("io.netty:netty-all:4.1.119.Final")
|
||||
dubboClientApacheImplementation("org.slf4j:slf4j-api:2.0.17")
|
||||
dubboClientApacheImplementation("ch.qos.logback:logback-classic:1.5.18")
|
||||
}
|
||||
|
||||
tasks.named<JavaCompile>(dubboClientCommon.compileJavaTaskName) {
|
||||
options.release.set(8)
|
||||
}
|
||||
|
||||
listOf(dubboClientAlibaba, dubboClientApache).forEach { sourceSet ->
|
||||
tasks.named<JavaCompile>(sourceSet.compileJavaTaskName) {
|
||||
options.release.set(8)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("dubboClientClasspath") {
|
||||
group = "verification"
|
||||
dependsOn(dubboClientAlibaba.classesTaskName, dubboClientApache.classesTaskName)
|
||||
doLast {
|
||||
layout.buildDirectory.file("dubbo-client-classpaths/alibaba.txt").get().asFile.apply {
|
||||
parentFile.mkdirs()
|
||||
writeText(dubboClientAlibaba.runtimeClasspath.asPath)
|
||||
}
|
||||
layout.buildDirectory.file("dubbo-client-classpaths/apache.txt").get().asFile.apply {
|
||||
parentFile.mkdirs()
|
||||
writeText(dubboClientApache.runtimeClasspath.asPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("classes") {
|
||||
dependsOn(dubboClientCommon.classesTaskName, dubboClientAlibaba.classesTaskName, dubboClientApache.classesTaskName)
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package io.github.reajason.dubbo.fixture.client.alibaba;
|
||||
|
||||
import com.alibaba.dubbo.common.utils.NetUtils;
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ReferenceConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.rpc.service.GenericService;
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
import io.github.reajason.dubbo.fixture.client.ClientRuntimeSupport;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class AlibabaDubboClient {
|
||||
|
||||
private static final String LOOPBACK_HOST = "127.0.0.1";
|
||||
|
||||
public static void main(String[] args) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
forceLoopbackLocalAddress();
|
||||
if (args.length < 1) {
|
||||
throw new IllegalArgumentException("usage: load-bytes <url> <base64> | run-command <url> <interfaceName> <command>");
|
||||
}
|
||||
if ("load-bytes".equals(args[0])) {
|
||||
if (args.length < 3) {
|
||||
throw new IllegalArgumentException("usage: load-bytes <url> <base64>");
|
||||
}
|
||||
System.out.println(loadBytes(args[1], args[2]));
|
||||
return;
|
||||
}
|
||||
if ("run-command".equals(args[0])) {
|
||||
if (args.length < 4) {
|
||||
throw new IllegalArgumentException("usage: run-command <url> <interfaceName> <command>");
|
||||
}
|
||||
Object result = runCommand(args[1], args[2], args[3]);
|
||||
if (result instanceof byte[]) {
|
||||
System.out.println(new String((byte[]) result, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
System.out.println(String.valueOf(result));
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("unsupported action: " + args[0]);
|
||||
}
|
||||
|
||||
public static String loadBytes(String url, String base64) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
forceLoopbackLocalAddress();
|
||||
ReferenceConfig<BytecodeLoadingService> reference = new ReferenceConfig<BytecodeLoadingService>();
|
||||
reference.setApplication(new ApplicationConfig("alibaba-dubbo-load-bytes-client"));
|
||||
reference.setRegistry(new RegistryConfig("N/A"));
|
||||
reference.setInterface(BytecodeLoadingService.class);
|
||||
reference.setCheck(false);
|
||||
reference.setTimeout(30000);
|
||||
reference.setRetries(0);
|
||||
reference.setUrl(url);
|
||||
|
||||
BytecodeLoadingService loadingService = reference.get();
|
||||
try {
|
||||
return loadingService.loadBytes(base64);
|
||||
} finally {
|
||||
reference.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object runCommand(String url, String interfaceName, String command) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
forceLoopbackLocalAddress();
|
||||
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
|
||||
reference.setApplication(new ApplicationConfig("alibaba-dubbo-command-client"));
|
||||
reference.setRegistry(new RegistryConfig("N/A"));
|
||||
reference.setInterface(interfaceName);
|
||||
reference.setGeneric(true);
|
||||
reference.setCheck(false);
|
||||
reference.setTimeout(30000);
|
||||
reference.setRetries(0);
|
||||
reference.setUrl(url);
|
||||
|
||||
GenericService genericService = reference.get();
|
||||
try {
|
||||
return genericService.$invoke(
|
||||
"handle",
|
||||
new String[]{byte[].class.getName()},
|
||||
new Object[]{command.getBytes(StandardCharsets.UTF_8)}
|
||||
);
|
||||
} finally {
|
||||
reference.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private static void forceLoopbackLocalAddress() {
|
||||
try {
|
||||
Field localAddressField = NetUtils.class.getDeclaredField("LOCAL_ADDRESS");
|
||||
localAddressField.setAccessible(true);
|
||||
localAddressField.set(null, InetAddress.getByName(LOOPBACK_HOST));
|
||||
} catch (Exception ignored) {
|
||||
// Best-effort workaround for Dubbo 2.6.x local address selection on macOS.
|
||||
}
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package io.github.reajason.dubbo.fixture.client.apache;
|
||||
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
import io.github.reajason.dubbo.fixture.client.ClientRuntimeSupport;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ApacheDubboClient {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
if (args.length < 1) {
|
||||
throw new IllegalArgumentException("usage: load-bytes <url> <base64> | run-command <url> <interfaceName> <command>");
|
||||
}
|
||||
if ("load-bytes".equals(args[0])) {
|
||||
if (args.length < 3) {
|
||||
throw new IllegalArgumentException("usage: load-bytes <url> <base64>");
|
||||
}
|
||||
System.out.println(loadBytes(args[1], args[2]));
|
||||
return;
|
||||
}
|
||||
if ("run-command".equals(args[0])) {
|
||||
if (args.length < 4) {
|
||||
throw new IllegalArgumentException("usage: run-command <url> <interfaceName> <command>");
|
||||
}
|
||||
Object result = runCommand(args[1], args[2], args[3]);
|
||||
if (result instanceof byte[]) {
|
||||
System.out.println(new String((byte[]) result, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
System.out.println(String.valueOf(result));
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("unsupported action: " + args[0]);
|
||||
}
|
||||
|
||||
public static String loadBytes(String url, String base64) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
ReferenceConfig<BytecodeLoadingService> reference = new ReferenceConfig<BytecodeLoadingService>();
|
||||
reference.setApplication(new ApplicationConfig("apache-dubbo-load-bytes-client"));
|
||||
reference.setRegistry(new RegistryConfig("N/A"));
|
||||
reference.setInterface(BytecodeLoadingService.class);
|
||||
reference.setCheck(false);
|
||||
reference.setTimeout(30000);
|
||||
reference.setRetries(0);
|
||||
reference.setUrl(url);
|
||||
|
||||
BytecodeLoadingService loadingService = reference.get();
|
||||
try {
|
||||
return loadingService.loadBytes(base64);
|
||||
} finally {
|
||||
reference.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object runCommand(String url, String interfaceName, String command) {
|
||||
ClientRuntimeSupport.prepareClientJvm();
|
||||
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
|
||||
reference.setApplication(new ApplicationConfig("apache-dubbo-command-client"));
|
||||
reference.setRegistry(new RegistryConfig("N/A"));
|
||||
reference.setInterface(interfaceName);
|
||||
reference.setGeneric(true);
|
||||
reference.setCheck(false);
|
||||
reference.setTimeout(30000);
|
||||
reference.setRetries(0);
|
||||
reference.setUrl(url);
|
||||
|
||||
GenericService genericService = reference.get();
|
||||
try {
|
||||
return genericService.$invoke(
|
||||
"handle",
|
||||
new String[]{byte[].class.getName()},
|
||||
new Object[]{command.getBytes(StandardCharsets.UTF_8)}
|
||||
);
|
||||
} finally {
|
||||
reference.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package io.github.reajason.dubbo.fixture.api;
|
||||
|
||||
public interface BytecodeLoadingService {
|
||||
String loadBytes(String base64);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package io.github.reajason.dubbo.fixture.client;
|
||||
|
||||
public final class ClientRuntimeSupport {
|
||||
|
||||
private static final String[] PROXY_PROPERTIES = new String[]{
|
||||
"proxyHost",
|
||||
"proxyPort",
|
||||
"http.proxyHost",
|
||||
"http.proxyPort",
|
||||
"https.proxyHost",
|
||||
"https.proxyPort",
|
||||
"socksProxyHost",
|
||||
"socksProxyPort",
|
||||
"ftp.proxyHost",
|
||||
"ftp.proxyPort"
|
||||
};
|
||||
|
||||
private ClientRuntimeSupport() {
|
||||
}
|
||||
|
||||
public static void prepareClientJvm() {
|
||||
System.setProperty("dubbo.compiler", "jdk");
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
System.setProperty("java.net.useSystemProxies", "false");
|
||||
for (String property : PROXY_PROPERTIES) {
|
||||
System.clearProperty(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("idea")
|
||||
}
|
||||
|
||||
group = "io.github.reajason"
|
||||
version = rootProject.version
|
||||
|
||||
val dubboProviderCommon: SourceSet by sourceSets.creating
|
||||
val dubboProviderAlibaba: SourceSet by sourceSets.creating
|
||||
val dubboProviderApache276: SourceSet by sourceSets.creating
|
||||
val dubboProviderApache277: SourceSet by sourceSets.creating
|
||||
val dubboProviderApache278: SourceSet by sourceSets.creating
|
||||
val dubboProviderApache2723: SourceSet by sourceSets.creating
|
||||
val dubboProviderApache336: SourceSet by sourceSets.creating
|
||||
|
||||
val dubboProviderCommonImplementation: Configuration by configurations.getting
|
||||
val dubboProviderAlibabaImplementation: Configuration by configurations.getting
|
||||
val dubboProviderApache276Implementation: Configuration by configurations.getting
|
||||
val dubboProviderApache277Implementation: Configuration by configurations.getting
|
||||
val dubboProviderApache278Implementation: Configuration by configurations.getting
|
||||
val dubboProviderApache2723Implementation: Configuration by configurations.getting
|
||||
val dubboProviderApache336Implementation: Configuration by configurations.getting
|
||||
|
||||
val dubboProviderCommonOutput = dubboProviderCommon.output
|
||||
|
||||
dubboProviderAlibaba.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderAlibaba.runtimeClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache276.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache276.runtimeClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache277.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache277.runtimeClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache278.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache278.runtimeClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache2723.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache2723.runtimeClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache336.compileClasspath += dubboProviderCommonOutput
|
||||
dubboProviderApache336.runtimeClasspath += dubboProviderCommonOutput
|
||||
|
||||
listOf(
|
||||
"dubboProviderApache336CompileClasspath",
|
||||
"dubboProviderApache336RuntimeClasspath"
|
||||
).forEach { configurationName ->
|
||||
configurations.named(configurationName) {
|
||||
exclude(group = "io.netty", module = "netty-transport-native-kqueue")
|
||||
exclude(group = "io.netty", module = "netty-resolver-dns-native-macos")
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs.add(file("src/main"))
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dubboProviderCommonImplementation("org.slf4j:slf4j-api:1.7.36")
|
||||
dubboProviderCommonImplementation("org.apache.dubbo:dubbo:2.7.23") {
|
||||
exclude(group = "log4j", module = "log4j")
|
||||
}
|
||||
|
||||
dubboProviderAlibabaImplementation(dubboProviderCommonOutput)
|
||||
dubboProviderAlibabaImplementation("com.alibaba:dubbo:2.6.12")
|
||||
dubboProviderAlibabaImplementation("org.apache.dubbo:dubbo:2.7.6")
|
||||
dubboProviderAlibabaImplementation("com.alibaba:hessian-lite:3.2.4")
|
||||
dubboProviderAlibabaImplementation("com.caucho:hessian:4.0.51")
|
||||
dubboProviderAlibabaImplementation("org.apache.httpcomponents:httpclient:4.5.3")
|
||||
dubboProviderAlibabaImplementation("org.springframework:spring-web:5.3.39")
|
||||
dubboProviderAlibabaImplementation("io.netty:netty-all:4.1.25.Final")
|
||||
dubboProviderAlibabaImplementation("org.mortbay.jetty:jetty:6.1.26")
|
||||
dubboProviderAlibabaImplementation("org.mortbay.jetty:jetty-util:6.1.26")
|
||||
dubboProviderAlibabaImplementation("org.slf4j:slf4j-api:1.7.36")
|
||||
dubboProviderAlibabaImplementation("ch.qos.logback:logback-classic:1.2.13")
|
||||
|
||||
fun apacheDubbo27Provider(configuration: Configuration, version: String, tomcatVersion: String) {
|
||||
add(configuration.name, dubboProviderCommonOutput)
|
||||
add(configuration.name, "org.apache.dubbo:dubbo:$version") {
|
||||
exclude(group = "log4j", module = "log4j")
|
||||
}
|
||||
add(configuration.name, "com.alibaba:hessian-lite:3.2.4")
|
||||
add(configuration.name, "com.caucho:hessian:4.0.51")
|
||||
add(configuration.name, "org.apache.httpcomponents:httpclient:4.5.13")
|
||||
add(configuration.name, "com.github.briandilley.jsonrpc4j:jsonrpc4j:1.2.0")
|
||||
add(configuration.name, "org.springframework:spring-web:5.3.39")
|
||||
add(configuration.name, "org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion")
|
||||
add(configuration.name, "org.mortbay.jetty:jetty:6.1.26")
|
||||
add(configuration.name, "org.mortbay.jetty:jetty-util:6.1.26")
|
||||
add(configuration.name, "org.slf4j:slf4j-api:1.7.36")
|
||||
add(configuration.name, "ch.qos.logback:logback-classic:1.2.13")
|
||||
}
|
||||
|
||||
apacheDubbo27Provider(dubboProviderApache276Implementation, "2.7.6", "8.5.100")
|
||||
apacheDubbo27Provider(dubboProviderApache277Implementation, "2.7.7", "8.5.100")
|
||||
apacheDubbo27Provider(dubboProviderApache278Implementation, "2.7.8", "9.0.104")
|
||||
apacheDubbo27Provider(dubboProviderApache2723Implementation, "2.7.23", "9.0.104")
|
||||
|
||||
dubboProviderApache336Implementation(dubboProviderCommonOutput)
|
||||
dubboProviderApache336Implementation("org.apache.dubbo:dubbo:3.3.6") {
|
||||
exclude(group = "log4j", module = "log4j")
|
||||
}
|
||||
dubboProviderApache336Implementation("org.apache.dubbo:dubbo-rpc-triple:3.3.6")
|
||||
dubboProviderApache336Implementation("org.apache.dubbo.extensions:dubbo-rpc-http:3.3.1")
|
||||
dubboProviderApache336Implementation("org.apache.dubbo.extensions:dubbo-rpc-hessian:3.3.0")
|
||||
dubboProviderApache336Implementation("org.apache.dubbo:dubbo-remoting-http:3.3.0-beta.2")
|
||||
dubboProviderApache336Implementation("com.caucho:hessian:4.0.51")
|
||||
dubboProviderApache336Implementation("io.netty:netty-all:4.1.119.Final")
|
||||
dubboProviderApache336Implementation("org.slf4j:slf4j-api:2.0.17")
|
||||
dubboProviderApache336Implementation("ch.qos.logback:logback-classic:1.5.18")
|
||||
}
|
||||
|
||||
tasks.named<JavaCompile>(dubboProviderCommon.compileJavaTaskName) {
|
||||
options.release.set(8)
|
||||
}
|
||||
|
||||
listOf(
|
||||
dubboProviderAlibaba,
|
||||
dubboProviderApache276,
|
||||
dubboProviderApache277,
|
||||
dubboProviderApache278,
|
||||
dubboProviderApache2723,
|
||||
dubboProviderApache336
|
||||
).forEach { sourceSet ->
|
||||
tasks.named<JavaCompile>(sourceSet.compileJavaTaskName) {
|
||||
options.release.set(8)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerDubboFatJar(
|
||||
taskName: String,
|
||||
sourceSet: SourceSet,
|
||||
mainClassName: String,
|
||||
mergeApacheProtocolSpi: Boolean = false
|
||||
): TaskProvider<Jar> {
|
||||
val protocolSpiPath = "META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol"
|
||||
val mergedProtocolSpi = layout.buildDirectory.file("generated/$taskName/$protocolSpiPath")
|
||||
val mergeTask = if (mergeApacheProtocolSpi) {
|
||||
tasks.register("${taskName}MergeProtocolSpi") {
|
||||
inputs.files(sourceSet.runtimeClasspath)
|
||||
outputs.file(mergedProtocolSpi)
|
||||
doLast {
|
||||
val outputFile = mergedProtocolSpi.get().asFile
|
||||
outputFile.parentFile.mkdirs()
|
||||
val mergedLines = linkedSetOf<String>()
|
||||
sourceSet.runtimeClasspath.files
|
||||
.filter { it.extension == "jar" }
|
||||
.forEach { runtimeJar ->
|
||||
zipTree(runtimeJar).matching {
|
||||
include(protocolSpiPath)
|
||||
}.forEach { spiFile ->
|
||||
spiFile.readLines()
|
||||
.map(String::trim)
|
||||
.filter { it.isNotEmpty() && !it.startsWith("#") }
|
||||
.forEach(mergedLines::add)
|
||||
}
|
||||
}
|
||||
outputFile.writeText(mergedLines.joinToString(System.lineSeparator()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return tasks.register<Jar>(taskName) {
|
||||
group = "verification"
|
||||
archiveClassifier.set(taskName.removePrefix("dubbo").removeSuffix("FatJar").lowercase())
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
dependsOn(sourceSet.classesTaskName, dubboProviderCommon.classesTaskName)
|
||||
manifest {
|
||||
attributes["Main-Class"] = mainClassName
|
||||
}
|
||||
from(sourceSet.output)
|
||||
from(dubboProviderCommon.output)
|
||||
if (mergeApacheProtocolSpi) {
|
||||
dependsOn(mergeTask)
|
||||
from({
|
||||
sourceSet.runtimeClasspath.files
|
||||
.filter { it.exists() }
|
||||
.map { if (it.isDirectory) it else zipTree(it) }
|
||||
}) {
|
||||
includeEmptyDirs = false
|
||||
exclude(protocolSpiPath)
|
||||
}
|
||||
into("META-INF/dubbo/internal") {
|
||||
from(mergedProtocolSpi) {
|
||||
rename { "org.apache.dubbo.rpc.Protocol" }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
from({
|
||||
sourceSet.runtimeClasspath.files
|
||||
.filter { it.exists() }
|
||||
.map { if (it.isDirectory) it else zipTree(it) }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dubboAlibabaProviderFatJar = registerDubboFatJar(
|
||||
"dubboAlibabaProviderFatJar",
|
||||
dubboProviderAlibaba,
|
||||
"io.github.reajason.dubbo.fixture.alibaba.AlibabaDubbo2Provider"
|
||||
)
|
||||
val dubboApache276ProviderFatJar = registerDubboFatJar(
|
||||
"dubboApache276ProviderFatJar",
|
||||
dubboProviderApache276,
|
||||
"io.github.reajason.dubbo.fixture.apache2.ApacheDubbo276Provider"
|
||||
)
|
||||
val dubboApache277ProviderFatJar = registerDubboFatJar(
|
||||
"dubboApache277ProviderFatJar",
|
||||
dubboProviderApache277,
|
||||
"io.github.reajason.dubbo.fixture.apache2.ApacheDubbo277Provider"
|
||||
)
|
||||
val dubboApache278ProviderFatJar = registerDubboFatJar(
|
||||
"dubboApache278ProviderFatJar",
|
||||
dubboProviderApache278,
|
||||
"io.github.reajason.dubbo.fixture.apache2.ApacheDubbo278Provider"
|
||||
)
|
||||
val dubboApache2723ProviderFatJar = registerDubboFatJar(
|
||||
"dubboApache2723ProviderFatJar",
|
||||
dubboProviderApache2723,
|
||||
"io.github.reajason.dubbo.fixture.apache2.ApacheDubbo2723Provider"
|
||||
)
|
||||
val dubboApache336ProviderFatJar = registerDubboFatJar(
|
||||
"dubboApache336ProviderFatJar",
|
||||
dubboProviderApache336,
|
||||
"io.github.reajason.dubbo.fixture.apache3.ApacheDubbo336Provider",
|
||||
mergeApacheProtocolSpi = true
|
||||
)
|
||||
|
||||
tasks.register("dubboProviderFatJars") {
|
||||
group = "verification"
|
||||
dependsOn(
|
||||
dubboAlibabaProviderFatJar,
|
||||
dubboApache276ProviderFatJar,
|
||||
dubboApache277ProviderFatJar,
|
||||
dubboApache278ProviderFatJar,
|
||||
dubboApache2723ProviderFatJar,
|
||||
dubboApache336ProviderFatJar
|
||||
)
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package io.github.reajason.dubbo.fixture.alibaba;
|
||||
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ProtocolConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.ServiceConfig;
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
import io.github.reajason.dubbo.fixture.api.DemoService;
|
||||
import io.github.reajason.dubbo.fixture.common.BytecodeLoadingServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.DemoServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.LoadBytesExportContext;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class AlibabaDubbo2Provider {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
System.setProperty("dubbo.compiler", "jdk");
|
||||
ApplicationConfig application = new ApplicationConfig("alibaba-dubbo2-provider");
|
||||
application.setQosEnable(true);
|
||||
application.setQosPort(22221);
|
||||
|
||||
ProtocolConfig dubboProtocol = new ProtocolConfig();
|
||||
dubboProtocol.setName("dubbo");
|
||||
dubboProtocol.setPort(20880);
|
||||
|
||||
ProtocolConfig hessianProtocol = new ProtocolConfig();
|
||||
hessianProtocol.setName("hessian");
|
||||
hessianProtocol.setPort(28080);
|
||||
|
||||
ProtocolConfig httpProtocol = new ProtocolConfig();
|
||||
httpProtocol.setName("http");
|
||||
httpProtocol.setPort(28081);
|
||||
|
||||
RegistryConfig registry = new RegistryConfig("N/A");
|
||||
LoadBytesExportContext.register(application, registry, Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
|
||||
ServiceConfig<DemoService> demoService = new ServiceConfig<DemoService>();
|
||||
demoService.setApplication(application);
|
||||
demoService.setRegistry(registry);
|
||||
demoService.setProtocols(Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
demoService.setInterface(DemoService.class);
|
||||
demoService.setRef(new DemoServiceImpl("alibaba-dubbo-2.6.12"));
|
||||
demoService.export();
|
||||
|
||||
ServiceConfig<BytecodeLoadingService> loaderService = new ServiceConfig<BytecodeLoadingService>();
|
||||
loaderService.setApplication(application);
|
||||
loaderService.setRegistry(registry);
|
||||
loaderService.setProtocols(Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
loaderService.setInterface(BytecodeLoadingService.class);
|
||||
loaderService.setRef(new BytecodeLoadingServiceImpl());
|
||||
loaderService.export();
|
||||
|
||||
System.out.println("==============================================");
|
||||
System.out.println(" alibaba-dubbo 2.6.12 Provider started");
|
||||
System.out.println(" dubbo -> dubbo://127.0.0.1:20880");
|
||||
System.out.println(" hessian -> hessian://127.0.0.1:28080");
|
||||
System.out.println(" http -> http://127.0.0.1:28081");
|
||||
System.out.println(" qos -> 127.0.0.1:22221");
|
||||
System.out.println("==============================================");
|
||||
|
||||
new CountDownLatch(1).await();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.github.reajason.dubbo.fixture.apache2;
|
||||
|
||||
public class ApacheDubbo2723Provider {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ApacheDubbo2Provider.start("apache-dubbo-2.7.23", 20881, 28082, 28083, 22222);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.github.reajason.dubbo.fixture.apache2;
|
||||
|
||||
public class ApacheDubbo276Provider {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ApacheDubbo2Provider.start("apache-dubbo-2.7.6", 20885, 28086, 28087, 22226);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.github.reajason.dubbo.fixture.apache2;
|
||||
|
||||
public class ApacheDubbo277Provider {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ApacheDubbo2Provider.start("apache-dubbo-2.7.7", 20886, 28088, 28089, 22227);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.github.reajason.dubbo.fixture.apache2;
|
||||
|
||||
public class ApacheDubbo278Provider {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ApacheDubbo2Provider.start("apache-dubbo-2.7.8", 20887, 28090, 28091, 22228);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package io.github.reajason.dubbo.fixture.apache3;
|
||||
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
import io.github.reajason.dubbo.fixture.api.DemoService;
|
||||
import io.github.reajason.dubbo.fixture.common.BytecodeLoadingServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.DemoServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.LoadBytesExportContext;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ProtocolConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.ServiceConfig;
|
||||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ApacheDubbo336Provider {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("dubbo.compiler", "jdk");
|
||||
ApplicationConfig application = new ApplicationConfig("apache-dubbo-3.3.6-provider");
|
||||
application.setQosEnable(true);
|
||||
application.setQosPort(22223);
|
||||
|
||||
RegistryConfig registry = new RegistryConfig("N/A");
|
||||
ProtocolConfig dubboProtocol = new ProtocolConfig("dubbo", 20882);
|
||||
ProtocolConfig triProtocol = new ProtocolConfig("tri", 50051);
|
||||
ProtocolConfig hessianProtocol = new ProtocolConfig("hessian", 28084);
|
||||
ProtocolConfig httpProtocol = new ProtocolConfig("http", 28085);
|
||||
LoadBytesExportContext.register(
|
||||
application,
|
||||
registry,
|
||||
Arrays.asList(dubboProtocol, triProtocol, hessianProtocol, httpProtocol)
|
||||
);
|
||||
|
||||
ServiceConfig<DemoService> demoService = new ServiceConfig<DemoService>();
|
||||
demoService.setInterface(DemoService.class);
|
||||
demoService.setRef(new DemoServiceImpl("apache-dubbo-3.3.6"));
|
||||
|
||||
ServiceConfig<BytecodeLoadingService> loaderService = new ServiceConfig<BytecodeLoadingService>();
|
||||
loaderService.setInterface(BytecodeLoadingService.class);
|
||||
loaderService.setRef(new BytecodeLoadingServiceImpl());
|
||||
|
||||
DubboBootstrap.getInstance()
|
||||
.application(application)
|
||||
.registry(registry)
|
||||
.protocol(dubboProtocol)
|
||||
.protocol(triProtocol)
|
||||
.protocol(hessianProtocol)
|
||||
.protocol(httpProtocol)
|
||||
.service(demoService)
|
||||
.service(loaderService)
|
||||
.start();
|
||||
|
||||
System.out.println("==============================================");
|
||||
System.out.println(" apache-dubbo-3.3.6 Provider started");
|
||||
System.out.println(" dubbo -> dubbo://127.0.0.1:20882");
|
||||
System.out.println(" tri -> tri://127.0.0.1:50051");
|
||||
System.out.println(" hessian -> hessian://127.0.0.1:28084");
|
||||
System.out.println(" http -> http://127.0.0.1:28085");
|
||||
System.out.println(" qos -> 127.0.0.1:22223");
|
||||
System.out.println("==============================================");
|
||||
|
||||
DubboBootstrap.getInstance().await();
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package io.github.reajason.dubbo.fixture.apache2;
|
||||
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
import io.github.reajason.dubbo.fixture.api.DemoService;
|
||||
import io.github.reajason.dubbo.fixture.common.BytecodeLoadingServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.DemoServiceImpl;
|
||||
import io.github.reajason.dubbo.fixture.common.LoadBytesExportContext;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ProtocolConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.ServiceConfig;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public final class ApacheDubbo2Provider {
|
||||
|
||||
private ApacheDubbo2Provider() {
|
||||
}
|
||||
|
||||
public static void start(String providerName, int dubboPort, int hessianPort, int httpPort, int qosPort)
|
||||
throws InterruptedException {
|
||||
System.setProperty("dubbo.compiler", "jdk");
|
||||
ApplicationConfig application = new ApplicationConfig(providerName + "-provider");
|
||||
application.setQosEnable(true);
|
||||
application.setQosPort(qosPort);
|
||||
|
||||
ProtocolConfig dubboProtocol = new ProtocolConfig();
|
||||
dubboProtocol.setName("dubbo");
|
||||
dubboProtocol.setPort(dubboPort);
|
||||
|
||||
ProtocolConfig hessianProtocol = new ProtocolConfig();
|
||||
hessianProtocol.setName("hessian");
|
||||
hessianProtocol.setPort(hessianPort);
|
||||
hessianProtocol.setServer("tomcat");
|
||||
|
||||
ProtocolConfig httpProtocol = new ProtocolConfig();
|
||||
httpProtocol.setName("http");
|
||||
httpProtocol.setPort(httpPort);
|
||||
httpProtocol.setServer("tomcat");
|
||||
|
||||
RegistryConfig registry = new RegistryConfig("N/A");
|
||||
LoadBytesExportContext.register(application, registry, Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
|
||||
ServiceConfig<DemoService> demoService = new ServiceConfig<DemoService>();
|
||||
demoService.setApplication(application);
|
||||
demoService.setRegistry(registry);
|
||||
demoService.setProtocols(Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
demoService.setInterface(DemoService.class);
|
||||
demoService.setRef(new DemoServiceImpl(providerName));
|
||||
demoService.export();
|
||||
|
||||
ServiceConfig<BytecodeLoadingService> loaderService = new ServiceConfig<BytecodeLoadingService>();
|
||||
loaderService.setApplication(application);
|
||||
loaderService.setRegistry(registry);
|
||||
loaderService.setProtocols(Arrays.asList(dubboProtocol, hessianProtocol, httpProtocol));
|
||||
loaderService.setInterface(BytecodeLoadingService.class);
|
||||
loaderService.setRef(new BytecodeLoadingServiceImpl());
|
||||
loaderService.export();
|
||||
|
||||
System.out.println("==============================================");
|
||||
System.out.println(" " + providerName + " Provider started");
|
||||
System.out.println(" dubbo -> dubbo://127.0.0.1:" + dubboPort);
|
||||
System.out.println(" hessian -> hessian://127.0.0.1:" + hessianPort);
|
||||
System.out.println(" http -> http://127.0.0.1:" + httpPort);
|
||||
System.out.println(" qos -> 127.0.0.1:" + qosPort);
|
||||
System.out.println("==============================================");
|
||||
|
||||
new CountDownLatch(1).await();
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package io.github.reajason.dubbo.fixture.api;
|
||||
|
||||
public interface BytecodeLoadingService {
|
||||
String loadBytes(String base64);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package io.github.reajason.dubbo.fixture.api;
|
||||
|
||||
public interface DemoService {
|
||||
String sayHello(String name);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.github.reajason.dubbo.fixture.common;
|
||||
|
||||
import io.github.reajason.dubbo.fixture.api.BytecodeLoadingService;
|
||||
|
||||
public class BytecodeLoadingServiceImpl implements BytecodeLoadingService {
|
||||
|
||||
@Override
|
||||
public String loadBytes(String base64) {
|
||||
return BytecodeLoadingSupport.loadBase64(base64);
|
||||
}
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
package io.github.reajason.dubbo.fixture.common;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
public final class BytecodeLoadingSupport {
|
||||
|
||||
private BytecodeLoadingSupport() {
|
||||
}
|
||||
|
||||
public static String loadBase64(String base64) {
|
||||
String normalized = normalizeBase64(base64);
|
||||
byte[] bytes = Base64.getMimeDecoder().decode(normalized);
|
||||
return loadClassBytes(bytes);
|
||||
}
|
||||
|
||||
public static String loadClassBytes(byte[] bytes) {
|
||||
requireClassBytes(bytes);
|
||||
try {
|
||||
return new PayloadClassLoader(hostClassLoader()).defineAndInstantiate(bytes);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalStateException("failed to load bytecode payload", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String normalizeBase64(String base64) {
|
||||
if (base64 == null) {
|
||||
throw new IllegalArgumentException("base64 must not be null");
|
||||
}
|
||||
String trimmed = base64.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
throw new IllegalArgumentException("base64 must not be blank");
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
private static void requireClassBytes(byte[] bytes) {
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
throw new IllegalArgumentException("class bytes must not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassLoader hostClassLoader() {
|
||||
ClassLoader classLoader = BytecodeLoadingSupport.class.getClassLoader();
|
||||
if (classLoader == null) {
|
||||
classLoader = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public static Class<?> defineIntoHostClassLoader(String className, byte[] bytes) {
|
||||
if (className == null || className.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("class name must not be blank");
|
||||
}
|
||||
requireClassBytes(bytes);
|
||||
|
||||
ClassLoader classLoader = hostClassLoader();
|
||||
Class<?> loadedClass = findLoadedClass(className, classLoader);
|
||||
if (loadedClass != null) {
|
||||
return loadedClass;
|
||||
}
|
||||
|
||||
try {
|
||||
return defineClass(className, bytes, classLoader);
|
||||
} catch (LinkageError e) {
|
||||
loadedClass = findLoadedClass(className, classLoader);
|
||||
if (loadedClass != null) {
|
||||
return loadedClass;
|
||||
}
|
||||
throw e;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalStateException("failed to define class in host class loader: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerWithDubboClassPool(String className, byte[] bytes) {
|
||||
if (className == null || className.trim().isEmpty() || bytes == null || bytes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> classPoolClass = null;
|
||||
List<Object> classPools = new ArrayList<Object>();
|
||||
try {
|
||||
classPoolClass = Class.forName("javassist.ClassPool", false, hostClassLoader());
|
||||
classPools.add(classPoolClass.getMethod("getDefault").invoke(null));
|
||||
classPools.addAll(dubboClassGeneratorPools());
|
||||
|
||||
for (Object classPool : classPools) {
|
||||
if (classPoolContains(classPoolClass, classPool, className)) {
|
||||
continue;
|
||||
}
|
||||
Method makeClass = classPoolClass.getMethod("makeClass", InputStream.class);
|
||||
makeClass.invoke(classPool, new ByteArrayInputStream(bytes));
|
||||
}
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// Javassist is not present for all clients.
|
||||
} catch (InvocationTargetException e) {
|
||||
if (classPoolClass != null && anyClassPoolContains(classPoolClass, classPools, className)) {
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("failed to register class with Dubbo Javassist pool: " + className, e.getCause());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalStateException("failed to register class with Dubbo Javassist pool: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> findLoadedClass(String className, ClassLoader classLoader) {
|
||||
try {
|
||||
return Class.forName(className, false, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> defineClass(String className, byte[] bytes, ClassLoader classLoader)
|
||||
throws ReflectiveOperationException {
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod(
|
||||
"defineClass",
|
||||
String.class,
|
||||
byte[].class,
|
||||
int.class,
|
||||
int.class,
|
||||
ProtectionDomain.class
|
||||
);
|
||||
defineClass.setAccessible(true);
|
||||
try {
|
||||
return (Class<?>) defineClass.invoke(
|
||||
classLoader,
|
||||
className,
|
||||
bytes,
|
||||
0,
|
||||
bytes.length,
|
||||
BytecodeLoadingSupport.class.getProtectionDomain()
|
||||
);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof LinkageError) {
|
||||
throw (LinkageError) cause;
|
||||
}
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
}
|
||||
if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Object> dubboClassGeneratorPools() {
|
||||
List<Object> classPools = new ArrayList<Object>();
|
||||
List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
|
||||
addClassLoader(classLoaders, hostClassLoader());
|
||||
addClassLoader(classLoaders, Thread.currentThread().getContextClassLoader());
|
||||
|
||||
for (ClassLoader classLoader : classLoaders) {
|
||||
addDubboClassGeneratorPool(classPools, "com.alibaba.dubbo.common.bytecode.ClassGenerator", classLoader);
|
||||
addDubboClassGeneratorPool(classPools, "org.apache.dubbo.common.bytecode.ClassGenerator", classLoader);
|
||||
}
|
||||
return classPools;
|
||||
}
|
||||
|
||||
private static void addClassLoader(List<ClassLoader> classLoaders, ClassLoader classLoader) {
|
||||
if (classLoader != null && !classLoaders.contains(classLoader)) {
|
||||
classLoaders.add(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addDubboClassGeneratorPool(List<Object> classPools, String className, ClassLoader classLoader) {
|
||||
try {
|
||||
Class<?> classGeneratorClass = Class.forName(className, false, hostClassLoader());
|
||||
Method getClassPool = classGeneratorClass.getMethod("getClassPool", ClassLoader.class);
|
||||
Object classPool = getClassPool.invoke(null, classLoader);
|
||||
if (classPool != null && !classPools.contains(classPool)) {
|
||||
classPools.add(classPool);
|
||||
}
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// This runtime is using the other Dubbo namespace.
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalStateException("failed to resolve Dubbo class pool from " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean anyClassPoolContains(Class<?> classPoolClass, List<Object> classPools, String className) {
|
||||
for (Object classPool : classPools) {
|
||||
try {
|
||||
if (classPoolContains(classPoolClass, classPool, className)) {
|
||||
return true;
|
||||
}
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean classPoolContains(Class<?> classPoolClass, Object classPool, String className)
|
||||
throws ReflectiveOperationException {
|
||||
try {
|
||||
Method getOrNull = classPoolClass.getMethod("getOrNull", String.class);
|
||||
return getOrNull.invoke(classPool, className) != null;
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
Method get = classPoolClass.getMethod("get", String.class);
|
||||
return get.invoke(classPool, className) != null;
|
||||
} catch (InvocationTargetException invocationTargetException) {
|
||||
Throwable cause = invocationTargetException.getCause();
|
||||
if (cause != null && "javassist.NotFoundException".equals(cause.getClass().getName())) {
|
||||
return false;
|
||||
}
|
||||
throw invocationTargetException;
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && "javassist.NotFoundException".equals(cause.getClass().getName())) {
|
||||
return false;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PayloadClassLoader extends ClassLoader {
|
||||
|
||||
private PayloadClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
private String defineAndInstantiate(byte[] bytes) throws ReflectiveOperationException {
|
||||
Thread thread = Thread.currentThread();
|
||||
ClassLoader original = thread.getContextClassLoader();
|
||||
thread.setContextClassLoader(this);
|
||||
try {
|
||||
Object instance = defineClass(bytes, 0, bytes.length).newInstance();
|
||||
return String.valueOf(instance);
|
||||
} finally {
|
||||
thread.setContextClassLoader(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.github.reajason.dubbo.fixture.common;
|
||||
|
||||
import io.github.reajason.dubbo.fixture.api.DemoService;
|
||||
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
|
||||
private final String providerName;
|
||||
|
||||
public DemoServiceImpl(String providerName) {
|
||||
this.providerName = providerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
return "Hello, " + name + " from " + providerName;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package io.github.reajason.dubbo.fixture.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class LoadBytesExportContext {
|
||||
|
||||
private static volatile Object application;
|
||||
private static volatile Object registry;
|
||||
private static volatile List<?> protocols;
|
||||
|
||||
private LoadBytesExportContext() {
|
||||
}
|
||||
|
||||
public static void register(Object applicationConfig, Object registryConfig, List<?> protocolConfigs) {
|
||||
application = applicationConfig;
|
||||
registry = registryConfig;
|
||||
protocols = protocolConfigs;
|
||||
}
|
||||
|
||||
public static Object application() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public static Object registry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public static List<?> protocols() {
|
||||
return protocols;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package io.github.reajason.dubbo.fixture.common;
|
||||
|
||||
public final class Noop {
|
||||
private Noop() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user