parent
d8e03a3bd6
commit
7ad75c6c0a
@ -0,0 +1,57 @@
|
|||||||
|
package com.xxl.job.core.biz.client;
|
||||||
|
|
||||||
|
import com.xxl.job.core.biz.ExecutorBiz;
|
||||||
|
import com.xxl.job.core.biz.model.LogParam;
|
||||||
|
import com.xxl.job.core.biz.model.LogResult;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
|
import com.xxl.job.core.biz.model.TriggerParam;
|
||||||
|
import com.xxl.job.core.util.XxlJobRemotingUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* admin api test
|
||||||
|
*
|
||||||
|
* @author xuxueli 2017-07-28 22:14:52
|
||||||
|
*/
|
||||||
|
public class ExecutorBizClient implements ExecutorBiz {
|
||||||
|
|
||||||
|
public ExecutorBizClient() {
|
||||||
|
}
|
||||||
|
public ExecutorBizClient(String addressUrl, String accessToken) {
|
||||||
|
this.addressUrl = addressUrl;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
|
||||||
|
// valid
|
||||||
|
if (!this.addressUrl.endsWith("/")) {
|
||||||
|
this.addressUrl = this.addressUrl + "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String addressUrl ;
|
||||||
|
private String accessToken;
|
||||||
|
private int timeout = 3;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnT<String> beat() {
|
||||||
|
return XxlJobRemotingUtil.postBody(addressUrl+"beat", accessToken, timeout, null, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReturnT<String> idleBeat(int jobId){
|
||||||
|
return XxlJobRemotingUtil.postBody(addressUrl+"idleBeat", accessToken, timeout, jobId, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnT<String> kill(int jobId) {
|
||||||
|
return XxlJobRemotingUtil.postBody(addressUrl + "kill", accessToken, timeout, jobId, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnT<LogResult> log(LogParam logParam) {
|
||||||
|
return XxlJobRemotingUtil.postBody(addressUrl + "log", accessToken, timeout, logParam, LogResult.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReturnT<String> run(TriggerParam triggerParam) {
|
||||||
|
return XxlJobRemotingUtil.postBody(addressUrl + "run", accessToken, timeout, triggerParam, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.xxl.job.core.biz.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xuxueli 2020-04-11 22:27
|
||||||
|
*/
|
||||||
|
public class LogParam implements Serializable {
|
||||||
|
private static final long serialVersionUID = 42L;
|
||||||
|
|
||||||
|
public LogParam(long logDateTim, long logId, int fromLineNum) {
|
||||||
|
this.logDateTim = logDateTim;
|
||||||
|
this.logId = logId;
|
||||||
|
this.fromLineNum = fromLineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long logDateTim;
|
||||||
|
private long logId;
|
||||||
|
private int fromLineNum;
|
||||||
|
|
||||||
|
public long getLogDateTim() {
|
||||||
|
return logDateTim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogDateTim(long logDateTim) {
|
||||||
|
this.logDateTim = logDateTim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLogId() {
|
||||||
|
return logId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogId(long logId) {
|
||||||
|
this.logId = logId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFromLineNum() {
|
||||||
|
return fromLineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromLineNum(int fromLineNum) {
|
||||||
|
this.fromLineNum = fromLineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
package com.xxl.job.core.server;
|
||||||
|
|
||||||
|
import com.xxl.job.core.biz.ExecutorBiz;
|
||||||
|
import com.xxl.job.core.biz.impl.ExecutorBizImpl;
|
||||||
|
import com.xxl.job.core.biz.model.LogParam;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
|
import com.xxl.job.core.biz.model.TriggerParam;
|
||||||
|
import com.xxl.job.core.thread.ExecutorRegistryThread;
|
||||||
|
import com.xxl.job.core.util.GsonTool;
|
||||||
|
import com.xxl.job.core.util.XxlJobRemotingUtil;
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.*;
|
||||||
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
import io.netty.util.internal.ThrowableUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy from : https://github.com/xuxueli/xxl-rpc
|
||||||
|
*
|
||||||
|
* @author xuxueli 2020-04-11 21:25
|
||||||
|
*/
|
||||||
|
public class EmbedServer {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);
|
||||||
|
|
||||||
|
private ExecutorBiz executorBiz;
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
public void start(final String address, final int port, final String appName, final String accessToken) {
|
||||||
|
executorBiz = new ExecutorBizImpl();
|
||||||
|
thread = new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
// param
|
||||||
|
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||||
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// start server
|
||||||
|
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||||
|
bootstrap.group(bossGroup, workerGroup)
|
||||||
|
.channel(NioServerSocketChannel.class)
|
||||||
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel channel) throws Exception {
|
||||||
|
channel.pipeline()
|
||||||
|
.addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS)) // beat 3N, close if idle
|
||||||
|
.addLast(new HttpServerCodec())
|
||||||
|
.addLast(new HttpObjectAggregator(5 * 1024 * 1024)) // merge request & reponse to FULL
|
||||||
|
.addLast(new EmbedHttpServerHandler(executorBiz, accessToken));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
|
||||||
|
// bind
|
||||||
|
ChannelFuture future = bootstrap.bind(port).sync();
|
||||||
|
|
||||||
|
logger.info(">>>>>>>>>>> xxl-job remoting server start success, nettype = {}, port = {}", EmbedServer.class, port);
|
||||||
|
|
||||||
|
// start registry
|
||||||
|
startRegistry(appName, address);
|
||||||
|
|
||||||
|
// wait util stop
|
||||||
|
future.channel().closeFuture().sync();
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
if (e instanceof InterruptedException) {
|
||||||
|
logger.info(">>>>>>>>>>> xxl-job remoting server stop.");
|
||||||
|
} else {
|
||||||
|
logger.error(">>>>>>>>>>> xxl-job remoting server error.", e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// stop
|
||||||
|
try {
|
||||||
|
workerGroup.shutdownGracefully();
|
||||||
|
bossGroup.shutdownGracefully();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
thread.setDaemon(true); // daemon, service jvm, user thread leave >>> daemon leave >>> jvm leave
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() throws Exception {
|
||||||
|
// destroy server thread
|
||||||
|
if (thread!=null && thread.isAlive()) {
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop registry
|
||||||
|
stopRegistry();
|
||||||
|
logger.info(">>>>>>>>>>> xxl-job remoting server destroy success.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------- registry ----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netty_http
|
||||||
|
*
|
||||||
|
* Copy from : https://github.com/xuxueli/xxl-rpc
|
||||||
|
*
|
||||||
|
* @author xuxueli 2015-11-24 22:25:15
|
||||||
|
*/
|
||||||
|
public static class EmbedHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(EmbedHttpServerHandler.class);
|
||||||
|
|
||||||
|
private ExecutorBiz executorBiz;
|
||||||
|
private String accessToken;
|
||||||
|
public EmbedHttpServerHandler(ExecutorBiz executorBiz, String accessToken) {
|
||||||
|
this.executorBiz = executorBiz;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void channelRead0(final ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
|
||||||
|
|
||||||
|
// request parse
|
||||||
|
//final byte[] requestBytes = ByteBufUtil.getBytes(msg.content()); // byteBuf.toString(io.netty.util.CharsetUtil.UTF_8);
|
||||||
|
String requestData = msg.content().toString(CharsetUtil.UTF_8);
|
||||||
|
String uri = msg.uri();
|
||||||
|
HttpMethod httpMethod = msg.method();
|
||||||
|
boolean keepAlive = HttpUtil.isKeepAlive(msg);
|
||||||
|
String accessTokenReq = msg.headers().get(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN);
|
||||||
|
|
||||||
|
// do invoke
|
||||||
|
Object responseObj = process(httpMethod, uri, requestData, accessTokenReq);
|
||||||
|
|
||||||
|
// to json
|
||||||
|
String responseJson = GsonTool.toJson(responseObj);
|
||||||
|
|
||||||
|
// write response
|
||||||
|
writeResponse(ctx, keepAlive, responseJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object process(HttpMethod httpMethod, String uri, String requestData, String accessTokenReq) {
|
||||||
|
|
||||||
|
// valid
|
||||||
|
if (HttpMethod.POST != httpMethod) {
|
||||||
|
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
|
||||||
|
}
|
||||||
|
if (uri==null || uri.trim().length()==0) {
|
||||||
|
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
|
||||||
|
}
|
||||||
|
if (accessToken!=null
|
||||||
|
&& accessToken.trim().length()>0
|
||||||
|
&& !accessToken.equals(accessTokenReq)) {
|
||||||
|
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// services mapping
|
||||||
|
try {
|
||||||
|
if ("/beat".equals(uri)) {
|
||||||
|
return executorBiz.beat();
|
||||||
|
} else if ("/idleBeat".equals(uri)) {
|
||||||
|
int jobId = GsonTool.fromJson(requestData, Integer.class);
|
||||||
|
return executorBiz.idleBeat(jobId);
|
||||||
|
} else if ("/kill".equals(uri)) {
|
||||||
|
int jobId = GsonTool.fromJson(requestData, Integer.class);
|
||||||
|
return executorBiz.kill(jobId);
|
||||||
|
} else if ("/log".equals(uri)) {
|
||||||
|
LogParam logParam = GsonTool.fromJson(requestData, LogParam.class);
|
||||||
|
return executorBiz.log(logParam);
|
||||||
|
} else if ("/run".equals(uri)) {
|
||||||
|
TriggerParam triggerParam = GsonTool.fromJson(requestData, TriggerParam.class);
|
||||||
|
return executorBiz.run(triggerParam);
|
||||||
|
} else {
|
||||||
|
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping("+ uri +") not found.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
return new ReturnT<String>(ReturnT.FAIL_CODE, "request error:" + ThrowableUtil.stackTraceToString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write response
|
||||||
|
*/
|
||||||
|
private void writeResponse(ChannelHandlerContext ctx, boolean keepAlive, String responseJson) {
|
||||||
|
// write response
|
||||||
|
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(responseJson, CharsetUtil.UTF_8)); // Unpooled.wrappedBuffer(responseJson)
|
||||||
|
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8"); // HttpHeaderValues.TEXT_PLAIN.toString()
|
||||||
|
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||||
|
if (keepAlive) {
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||||
|
}
|
||||||
|
ctx.writeAndFlush(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
ctx.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
logger.error(">>>>>>>>>>> xxl-job provider netty_http server caught exception", cause);
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||||
|
if (evt instanceof IdleStateEvent) {
|
||||||
|
ctx.channel().close(); // beat 3N, close if idle
|
||||||
|
logger.debug(">>>>>>>>>>> xxl-job provider netty_http server close an idle channel.");
|
||||||
|
} else {
|
||||||
|
super.userEventTriggered(ctx, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- registry ----------------------
|
||||||
|
|
||||||
|
public void startRegistry(final String appName, final String address) {
|
||||||
|
// start registry
|
||||||
|
ExecutorRegistryThread.getInstance().start(appName, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopRegistry() {
|
||||||
|
// stop registry
|
||||||
|
ExecutorRegistryThread.getInstance().toStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.xxl.job.core.util;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xuxueli 2020-04-11 20:56:31
|
||||||
|
*/
|
||||||
|
public class GsonTool {
|
||||||
|
|
||||||
|
private static Gson gson = null;
|
||||||
|
static {
|
||||||
|
gson= new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object 转成 json
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String toJson(Object src) {
|
||||||
|
return gson.toJson(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json 转成 特定的cls的Object
|
||||||
|
*
|
||||||
|
* @param json
|
||||||
|
* @param classOfT
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T fromJson(String json, Class<T> classOfT) {
|
||||||
|
return gson.fromJson(json, classOfT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json 转成 特定的 rawClass<classOfT> 的Object
|
||||||
|
*
|
||||||
|
* @param json
|
||||||
|
* @param classOfT
|
||||||
|
* @param argClassOfT
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {
|
||||||
|
Type type = new ParameterizedType4ReturnT(classOfT, new Class[]{argClassOfT});
|
||||||
|
return gson.fromJson(json, type);
|
||||||
|
}
|
||||||
|
public static class ParameterizedType4ReturnT implements ParameterizedType {
|
||||||
|
private final Class raw;
|
||||||
|
private final Type[] args;
|
||||||
|
public ParameterizedType4ReturnT(Class raw, Type[] args) {
|
||||||
|
this.raw = raw;
|
||||||
|
this.args = args != null ? args : new Type[0];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Type[] getActualTypeArguments() {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Type getRawType() {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Type getOwnerType() {return null;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json 转成 特定的cls的list
|
||||||
|
*
|
||||||
|
* @param json
|
||||||
|
* @param classOfT
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> List<T> fromJsonList(String json, Class<T> classOfT) {
|
||||||
|
return gson.fromJson(
|
||||||
|
json,
|
||||||
|
new TypeToken<List<T>>() {
|
||||||
|
}.getType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,203 @@
|
|||||||
|
package com.xxl.job.core.util;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip tool
|
||||||
|
*
|
||||||
|
* @author xuxueli 2016-5-22 11:38:05
|
||||||
|
*/
|
||||||
|
public class IpUtil {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(IpUtil.class);
|
||||||
|
|
||||||
|
private static final String ANYHOST_VALUE = "0.0.0.0";
|
||||||
|
private static final String LOCALHOST_VALUE = "127.0.0.1";
|
||||||
|
private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static volatile InetAddress LOCAL_ADDRESS = null;
|
||||||
|
|
||||||
|
// ---------------------- valid ----------------------
|
||||||
|
|
||||||
|
private static InetAddress toValidAddress(InetAddress address) {
|
||||||
|
if (address instanceof Inet6Address) {
|
||||||
|
Inet6Address v6Address = (Inet6Address) address;
|
||||||
|
if (isPreferIPV6Address()) {
|
||||||
|
return normalizeV6Address(v6Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isValidV4Address(address)) {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPreferIPV6Address() {
|
||||||
|
return Boolean.getBoolean("java.net.preferIPv6Addresses");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid Inet4Address
|
||||||
|
*
|
||||||
|
* @param address
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean isValidV4Address(InetAddress address) {
|
||||||
|
if (address == null || address.isLoopbackAddress()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String name = address.getHostAddress();
|
||||||
|
boolean result = (name != null
|
||||||
|
&& IP_PATTERN.matcher(name).matches()
|
||||||
|
&& !ANYHOST_VALUE.equals(name)
|
||||||
|
&& !LOCALHOST_VALUE.equals(name));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalize the ipv6 Address, convert scope name to scope id.
|
||||||
|
* e.g.
|
||||||
|
* convert
|
||||||
|
* fe80:0:0:0:894:aeec:f37d:23e1%en0
|
||||||
|
* to
|
||||||
|
* fe80:0:0:0:894:aeec:f37d:23e1%5
|
||||||
|
* <p>
|
||||||
|
* The %5 after ipv6 address is called scope id.
|
||||||
|
* see java doc of {@link Inet6Address} for more details.
|
||||||
|
*
|
||||||
|
* @param address the input address
|
||||||
|
* @return the normalized address, with scope id converted to int
|
||||||
|
*/
|
||||||
|
private static InetAddress normalizeV6Address(Inet6Address address) {
|
||||||
|
String addr = address.getHostAddress();
|
||||||
|
int i = addr.lastIndexOf('%');
|
||||||
|
if (i > 0) {
|
||||||
|
try {
|
||||||
|
return InetAddress.getByName(addr.substring(0, i) + '%' + address.getScopeId());
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
// ignore
|
||||||
|
logger.debug("Unknown IPV6 address: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- find ip ----------------------
|
||||||
|
|
||||||
|
|
||||||
|
private static InetAddress getLocalAddress0() {
|
||||||
|
InetAddress localAddress = null;
|
||||||
|
try {
|
||||||
|
localAddress = InetAddress.getLocalHost();
|
||||||
|
InetAddress addressItem = toValidAddress(localAddress);
|
||||||
|
if (addressItem != null) {
|
||||||
|
return addressItem;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||||
|
if (null == interfaces) {
|
||||||
|
return localAddress;
|
||||||
|
}
|
||||||
|
while (interfaces.hasMoreElements()) {
|
||||||
|
try {
|
||||||
|
NetworkInterface network = interfaces.nextElement();
|
||||||
|
if (network.isLoopback() || network.isVirtual() || !network.isUp()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Enumeration<InetAddress> addresses = network.getInetAddresses();
|
||||||
|
while (addresses.hasMoreElements()) {
|
||||||
|
try {
|
||||||
|
InetAddress addressItem = toValidAddress(addresses.nextElement());
|
||||||
|
if (addressItem != null) {
|
||||||
|
try {
|
||||||
|
if(addressItem.isReachable(100)){
|
||||||
|
return addressItem;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return localAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------- tool ----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find first valid IP from local network card
|
||||||
|
*
|
||||||
|
* @return first valid local IP
|
||||||
|
*/
|
||||||
|
public static InetAddress getLocalAddress() {
|
||||||
|
if (LOCAL_ADDRESS != null) {
|
||||||
|
return LOCAL_ADDRESS;
|
||||||
|
}
|
||||||
|
InetAddress localAddress = getLocalAddress0();
|
||||||
|
LOCAL_ADDRESS = localAddress;
|
||||||
|
return localAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get ip address
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String getIp(){
|
||||||
|
return getLocalAddress().getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get ip:port
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String getIpPort(int port){
|
||||||
|
String ip = getIp();
|
||||||
|
return getIpPort(ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getIpPort(String ip, int port){
|
||||||
|
if (ip==null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ip.concat(":").concat(String.valueOf(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object[] parseIpPort(String address){
|
||||||
|
String[] array = address.split(":");
|
||||||
|
|
||||||
|
String host = array[0];
|
||||||
|
int port = Integer.parseInt(array[1]);
|
||||||
|
|
||||||
|
return new Object[]{host, port};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.xxl.job.core.util;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* net util
|
||||||
|
*
|
||||||
|
* @author xuxueli 2017-11-29 17:00:25
|
||||||
|
*/
|
||||||
|
public class NetUtil {
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(NetUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find avaliable port
|
||||||
|
*
|
||||||
|
* @param defaultPort
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int findAvailablePort(int defaultPort) {
|
||||||
|
int portTmp = defaultPort;
|
||||||
|
while (portTmp < 65535) {
|
||||||
|
if (!isPortUsed(portTmp)) {
|
||||||
|
return portTmp;
|
||||||
|
} else {
|
||||||
|
portTmp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portTmp = defaultPort--;
|
||||||
|
while (portTmp > 0) {
|
||||||
|
if (!isPortUsed(portTmp)) {
|
||||||
|
return portTmp;
|
||||||
|
} else {
|
||||||
|
portTmp--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("no available port.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check port used
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isPortUsed(int port) {
|
||||||
|
boolean used = false;
|
||||||
|
ServerSocket serverSocket = null;
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(port);
|
||||||
|
used = false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.info(">>>>>>>>>>> xxl-rpc, port[{}] is in use.", port);
|
||||||
|
used = true;
|
||||||
|
} finally {
|
||||||
|
if (serverSocket != null) {
|
||||||
|
try {
|
||||||
|
serverSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.info("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,145 +0,0 @@
|
|||||||
package com.xxl.job.core.biz.impl;
|
|
||||||
|
|
||||||
import com.xxl.job.core.biz.ExecutorBiz;
|
|
||||||
import com.xxl.job.core.biz.model.LogResult;
|
|
||||||
import com.xxl.job.core.biz.model.ReturnT;
|
|
||||||
import com.xxl.job.core.biz.model.TriggerParam;
|
|
||||||
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
|
||||||
import com.xxl.job.core.executor.XxlJobExecutor;
|
|
||||||
import com.xxl.job.core.glue.GlueTypeEnum;
|
|
||||||
import com.xxl.rpc.remoting.invoker.call.CallType;
|
|
||||||
import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;
|
|
||||||
import com.xxl.rpc.remoting.invoker.route.LoadBalance;
|
|
||||||
import com.xxl.rpc.remoting.net.impl.netty_http.client.NettyHttpClient;
|
|
||||||
import com.xxl.rpc.serialize.impl.HessianSerializer;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
|
|
||||||
public class ExecutorBizImplTest {
|
|
||||||
|
|
||||||
public XxlJobExecutor xxlJobExecutor = null;
|
|
||||||
public ExecutorBiz executorBiz = null;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() throws Exception {
|
|
||||||
|
|
||||||
// init executor
|
|
||||||
xxlJobExecutor = new XxlJobExecutor();
|
|
||||||
xxlJobExecutor.setAdminAddresses(null);
|
|
||||||
xxlJobExecutor.setAppName("xxl-job-executor-sample");
|
|
||||||
xxlJobExecutor.setIp(null);
|
|
||||||
xxlJobExecutor.setPort(9999);
|
|
||||||
xxlJobExecutor.setAccessToken(null);
|
|
||||||
xxlJobExecutor.setLogPath("/data/applogs/xxl-job/jobhandler");
|
|
||||||
xxlJobExecutor.setLogRetentionDays(-1);
|
|
||||||
|
|
||||||
// start executor
|
|
||||||
xxlJobExecutor.start();
|
|
||||||
|
|
||||||
TimeUnit.SECONDS.sleep(3);
|
|
||||||
|
|
||||||
// init executor biz proxy
|
|
||||||
XxlRpcReferenceBean referenceBean = new XxlRpcReferenceBean();
|
|
||||||
referenceBean.setClient(NettyHttpClient.class);
|
|
||||||
referenceBean.setSerializer(HessianSerializer.class);
|
|
||||||
referenceBean.setCallType(CallType.SYNC);
|
|
||||||
referenceBean.setLoadBalance(LoadBalance.ROUND);
|
|
||||||
referenceBean.setIface(ExecutorBiz.class);
|
|
||||||
referenceBean.setVersion(null);
|
|
||||||
referenceBean.setTimeout(3000);
|
|
||||||
referenceBean.setAddress("127.0.0.1:9999");
|
|
||||||
referenceBean.setAccessToken(null);
|
|
||||||
referenceBean.setInvokeCallback(null);
|
|
||||||
referenceBean.setInvokerFactory(null);
|
|
||||||
|
|
||||||
executorBiz = (ExecutorBiz) referenceBean.getObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after(){
|
|
||||||
if (xxlJobExecutor != null) {
|
|
||||||
xxlJobExecutor.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void beat() {
|
|
||||||
// Act
|
|
||||||
final ReturnT<String> retval = executorBiz.beat();
|
|
||||||
|
|
||||||
// Assert result
|
|
||||||
Assert.assertNotNull(retval);
|
|
||||||
Assert.assertNull(((ReturnT<String>) retval).getContent());
|
|
||||||
Assert.assertEquals(200, retval.getCode());
|
|
||||||
Assert.assertNull(retval.getMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void idleBeat(){
|
|
||||||
final int jobId = 0;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
final ReturnT<String> retval = executorBiz.idleBeat(jobId);
|
|
||||||
|
|
||||||
// Assert result
|
|
||||||
Assert.assertNotNull(retval);
|
|
||||||
Assert.assertNull(((ReturnT<String>) retval).getContent());
|
|
||||||
Assert.assertEquals(500, retval.getCode());
|
|
||||||
Assert.assertEquals("job thread is running or has trigger queue.", retval.getMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void kill(){
|
|
||||||
final int jobId = 0;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
final ReturnT<String> retval = executorBiz.kill(jobId);
|
|
||||||
|
|
||||||
// Assert result
|
|
||||||
Assert.assertNotNull(retval);
|
|
||||||
Assert.assertNull(((ReturnT<String>) retval).getContent());
|
|
||||||
Assert.assertEquals(200, retval.getCode());
|
|
||||||
Assert.assertNull(retval.getMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void log(){
|
|
||||||
final long logDateTim = 0L;
|
|
||||||
final long logId = 0;
|
|
||||||
final int fromLineNum = 0;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
final ReturnT<LogResult> retval = executorBiz.log(logDateTim, logId, fromLineNum);
|
|
||||||
|
|
||||||
// Assert result
|
|
||||||
Assert.assertNotNull(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void run(){
|
|
||||||
// trigger data
|
|
||||||
final TriggerParam triggerParam = new TriggerParam();
|
|
||||||
triggerParam.setJobId(1);
|
|
||||||
triggerParam.setExecutorHandler("demoJobHandler");
|
|
||||||
triggerParam.setExecutorParams(null);
|
|
||||||
triggerParam.setExecutorBlockStrategy(ExecutorBlockStrategyEnum.COVER_EARLY.name());
|
|
||||||
triggerParam.setGlueType(GlueTypeEnum.BEAN.name());
|
|
||||||
triggerParam.setGlueSource(null);
|
|
||||||
triggerParam.setGlueUpdatetime(System.currentTimeMillis());
|
|
||||||
triggerParam.setLogId(1);
|
|
||||||
triggerParam.setLogDateTime(System.currentTimeMillis());
|
|
||||||
|
|
||||||
// Act
|
|
||||||
final ReturnT<String> retval = executorBiz.run(triggerParam);
|
|
||||||
|
|
||||||
// Assert result
|
|
||||||
Assert.assertNotNull(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in new issue