diff --git a/build.gradle b/build.gradle index 1e6e4c8..2d1212d 100644 --- a/build.gradle +++ b/build.gradle @@ -23,8 +23,9 @@ dependencies { implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' // implementation 'com.github.darrachequesne:spring-data-jpa-datatables:5.1.0' implementation 'org.apache.commons:commons-lang3:3.10' - implementation group: 'commons-io', name: 'commons-io', version: '2.6' + implementation 'commons-io:commons-io:2.6' implementation 'com.jayway.jsonpath:json-path:2.4.0' + implementation 'io.netty:netty-all:4.1.60.Final' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpec.java b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpec.java new file mode 100644 index 0000000..cbea2aa --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpec.java @@ -0,0 +1,191 @@ +package com.eactive.httpmockserver.socket; + +import java.io.Serializable; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; + +@SuppressWarnings("serial") +@Entity +public class BytesMessageSpec implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Column(length = 100, nullable = false) + private String specName; + + @Column(length = 1) + private String llFieldInclude; + + @Column(length = 1) + private String llFieldLengthInclude; + + @Positive + private Integer llFieldLength; + + private Integer llFieldLengthAlpha; + + @PositiveOrZero + private Integer llFieldOffset; + + @Column(length = 20) + private String llFieldType; + + @Column(length = 20) + private String encode; + + @Positive + private Integer port; + + @Positive + private Integer sleepSeconds; + + @Column + @Lob + private String responseBody; + + @Column(length = 1) + private String useYn; + + @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @JoinColumn(name = "BYTE_MESSAGE_SPEC_ID") + @OrderBy("position") + private List EchoReplaceStringList; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getSpecName() { + return specName; + } + + public void setSpecName(String specName) { + this.specName = specName; + } + + public String getLlFieldInclude() { + return llFieldInclude; + } + + public void setLlFieldInclude(String llFieldInclude) { + this.llFieldInclude = llFieldInclude; + } + + public String getLlFieldLengthInclude() { + return llFieldLengthInclude; + } + + public void setLlFieldLengthInclude(String llFieldLengthInclude) { + this.llFieldLengthInclude = llFieldLengthInclude; + } + + public Integer getLlFieldLength() { + return llFieldLength; + } + + public void setLlFieldLength(Integer llFieldLength) { + this.llFieldLength = llFieldLength; + } + + public Integer getLlFieldLengthAlpha() { + return llFieldLengthAlpha; + } + + public void setLlFieldLengthAlpha(Integer llFieldLengthAlpha) { + this.llFieldLengthAlpha = llFieldLengthAlpha; + } + + public Integer getLlFieldOffset() { + return llFieldOffset; + } + + public void setLlFieldOffset(Integer llFieldOffset) { + this.llFieldOffset = llFieldOffset; + } + + public String getLlFieldType() { + return llFieldType; + } + + public void setLlFieldType(String llFieldType) { + this.llFieldType = llFieldType; + } + + public String getEncode() { + return encode; + } + + public void setEncode(String encode) { + this.encode = encode; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Integer getSleepSeconds() { + return sleepSeconds; + } + + public void setSleepSeconds(Integer sleepSeconds) { + this.sleepSeconds = sleepSeconds; + } + + public String getResponseBody() { + return responseBody; + } + + public void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + + public String getUseYn() { + return useYn; + } + + public void setUseYn(String useYn) { + this.useYn = useYn; + } + + public List getEchoReplaceStringList() { + return EchoReplaceStringList; + } + + public void setEchoReplaceStringList(List echoReplaceStringList) { + EchoReplaceStringList = echoReplaceStringList; + } + + @Override + public String toString() { + return "BytesMessageSpec [id=" + id + ", specName=" + specName + ", llFieldInclude=" + llFieldInclude + + ", llFieldLengthInclude=" + llFieldLengthInclude + ", llFieldLength=" + llFieldLength + + ", llFieldLengthAlpha=" + llFieldLengthAlpha + ", llFieldOffset=" + llFieldOffset + ", llFieldType=" + + llFieldType + ", encode=" + encode + ", port=" + port + ", sleepSeconds=" + sleepSeconds + + ", responseBody=" + responseBody + ", useYn=" + useYn + ", EchoReplaceStringList=" + + EchoReplaceStringList + "]"; + } +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecDao.java b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecDao.java new file mode 100644 index 0000000..d0923be --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecDao.java @@ -0,0 +1,9 @@ +package com.eactive.httpmockserver.socket; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BytesMessageSpecDao extends JpaRepository { + BytesMessageSpec findFirstByUseYn(String useYn); +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecService.java b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecService.java new file mode 100644 index 0000000..7728ee9 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecService.java @@ -0,0 +1,5 @@ +package com.eactive.httpmockserver.socket; + +public interface BytesMessageSpecService { + public BytesMessageSpec findActiveBytesMessageSpec(); +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecServiceImpl.java b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecServiceImpl.java new file mode 100644 index 0000000..d28536a --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/BytesMessageSpecServiceImpl.java @@ -0,0 +1,18 @@ +package com.eactive.httpmockserver.socket; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(propagation = Propagation.SUPPORTS) +public class BytesMessageSpecServiceImpl implements BytesMessageSpecService { + @Autowired + private BytesMessageSpecDao dao; + + @Override + public BytesMessageSpec findActiveBytesMessageSpec() { + return dao.findFirstByUseYn("Y"); + } +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/EchoReplaceString.java b/src/main/java/com/eactive/httpmockserver/socket/EchoReplaceString.java new file mode 100644 index 0000000..cc8a916 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/EchoReplaceString.java @@ -0,0 +1,57 @@ +package com.eactive.httpmockserver.socket; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.PositiveOrZero; + +@SuppressWarnings("serial") +@Entity +public class EchoReplaceString implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @PositiveOrZero + @Column(nullable = false) + private Integer position; + + @NotBlank + @Column(length = 5000, nullable = false) + private String replaceString; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public String getReplaceString() { + return replaceString; + } + + public void setReplaceString(String replaceString) { + this.replaceString = replaceString; + } + + @Override + public String toString() { + return "EchoReplaceString [id=" + id + ", position=" + position + ", replaceString=" + replaceString + "]"; + } +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServer.java b/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServer.java index 169f121..7ae6996 100644 --- a/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServer.java +++ b/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServer.java @@ -1,73 +1,84 @@ -//package com.eactive.httpmockserver.socket; -// -//import java.nio.ByteOrder; -// -//import javax.annotation.PreDestroy; -// -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.stereotype.Component; -// -//import io.netty.bootstrap.ServerBootstrap; -//import io.netty.channel.Channel; -//import io.netty.channel.ChannelFuture; -//import io.netty.channel.ChannelInitializer; -//import io.netty.channel.ChannelOption; -//import io.netty.channel.ChannelPipeline; -//import io.netty.channel.EventLoopGroup; -//import io.netty.channel.nio.NioEventLoopGroup; -//import io.netty.channel.socket.SocketChannel; -//import io.netty.channel.socket.nio.NioServerSocketChannel; -//import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -//import io.netty.handler.codec.LengthFieldPrepender; -//import io.netty.handler.codec.string.StringDecoder; -//import io.netty.util.CharsetUtil; -// -//@Component -//public class EchoSocketServer { -// private final Logger logger = LoggerFactory.getLogger(this.getClass()); -// -// private Channel channel; -// -// public void start() { -// EventLoopGroup bossGroup = new NioEventLoopGroup(); -// EventLoopGroup workerGroup = new NioEventLoopGroup(); -// try { -// ServerBootstrap server = new ServerBootstrap(); -// // @formatter:off -// server.group(bossGroup, workerGroup) -// .channel(NioServerSocketChannel.class) -// .childHandler(new ChannelInitializer() { -// @Override -// protected void initChannel(SocketChannel ch) throws Exception { -// ChannelPipeline pipeline = ch.pipeline(); -// //pipeline.addLast(new LengthFieldBasedFrameDecoder (ByteOrder.LITTLE_ENDIAN,Integer.MAX_VALUE,0,8,0,8,true)); -// //pipeline.addLast(new LengthFieldPrepender(8)); -// //pipeline.addLast(new LengthFieldBasedFrameDecoder (Integer.MAX_VALUE,0,8,0,8)); -// //pipeline.addLast(new LengthFieldBasedFrameDecoder (Integer.MAX_VALUE,0,2,0,2)); -// //pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); -// pipeline.addLast(new EchoSocketServerHandler()); -// } -// }) -// .option(ChannelOption.SO_BACKLOG, 128) -// .childOption(ChannelOption.SO_KEEPALIVE, false); -// // @formatter:on -// -// ChannelFuture channelFuture = server.bind(28181).sync(); -// channel = channelFuture.channel().closeFuture().sync().channel(); -// } catch (Exception e) { -// logger.error(e.getMessage()); -// } finally { -// bossGroup.shutdownGracefully(); -// workerGroup.shutdownGracefully(); -// } -// } -// -// @PreDestroy -// public void stop() { -// if (channel != null) { -// channel.close(); -// channel.parent().closeFuture(); -// } -// } -//} +package com.eactive.httpmockserver.socket; + +import javax.annotation.PreDestroy; +import javax.persistence.NoResultException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; + +@Component +public class EchoSocketServer { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private BytesMessageSpec spec; + + EventLoopGroup bossGroup; + EventLoopGroup workerGroup; + ChannelFuture channelFuture; + + public EchoSocketServer() { + } + + public EchoSocketServer(BytesMessageSpec spec) { + this.spec = spec; + } + + public void start() throws Exception { + if (spec == null) { + throw new NoResultException(); + } + + int port = (spec.getPort() == null ? 38181 : spec.getPort().intValue()); + bossGroup = new NioEventLoopGroup(); + workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap server = new ServerBootstrap(); + // @formatter:off + server.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new LengthHeaderFrameDecoder(spec)); + pipeline.addLast(new EchoSocketServerHandler(spec)); + } + }) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, false); + // @formatter:on + + channelFuture = server.bind(port).sync(); + channelFuture.channel().closeFuture().sync().channel(); + logger.info(port + " port bounded"); + } catch (Exception e) { + logger.error(e.getMessage()); + throw e; + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + @PreDestroy + public void stop() { + try { + bossGroup.shutdownGracefully().sync(); + workerGroup.shutdownGracefully().sync(); + channelFuture.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServerHandler.java b/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServerHandler.java index 4b895c7..0cbf209 100644 --- a/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServerHandler.java +++ b/src/main/java/com/eactive/httpmockserver/socket/EchoSocketServerHandler.java @@ -1,72 +1,144 @@ -//package com.eactive.httpmockserver.socket; -// -//import java.nio.charset.StandardCharsets; -// -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.stereotype.Component; -// -//import io.netty.buffer.ByteBuf; -//import io.netty.channel.ChannelHandler.Sharable; -//import io.netty.channel.ChannelHandlerContext; -//import io.netty.channel.ChannelInboundHandlerAdapter; -// -//@Component -//@Sharable -//public class EchoSocketServerHandler extends ChannelInboundHandlerAdapter { -// private final Logger logger = LoggerFactory.getLogger(this.getClass()); -// -// private int DATA_LENGTH = 2048; -// private ByteBuf buff; -// -// @Override -// public void handlerAdded(ChannelHandlerContext ctx) { -// logger.info("EchoSocketServer handlerAdded"); -// buff = ctx.alloc().buffer(DATA_LENGTH); -// } -// -// @Override -// public void channelActive(ChannelHandlerContext ctx) { -// logger.info("Remote Address: " + ctx.channel().remoteAddress().toString()); -// } -// -// @Override -// public void channelRead(ChannelHandlerContext ctx, Object msg) { -// logger.info("EchoSocketServer channelRead"); -//// ByteBuf buf = (ByteBuf) msg; -//// byte[] bytes = new byte[buf.readableBytes()]; -//// buf.readBytes(bytes); -//// String data = new String(bytes, StandardCharsets.UTF_8); -// -//// ByteBuf mBuf = (ByteBuf) msg; -//// buff.writeBytes(mBuf); // Ŭ¶óÀÌ¾ðÆ®¿¡¼­ º¸³»´Â µ¥ÀÌÅͰ¡ ÃàÀûµÊ -//// mBuf.release(); -//// -//// //final ChannelFuture f = ctx.writeAndFlush(buff); -//// -//// System.out.println("TcpServer: " + buff.toString()); -//// ctx.writeAndFlush(buff); -// -// String message = ((ByteBuf) msg).toString(); -// System.out.println("message=" + message); -// ctx.write(msg); -// } -// -// @Override -// public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { -// logger.info("EchoSocketServer channelReadComplete"); -// ctx.flush(); -// } -// -// @Override -// public void handlerRemoved(ChannelHandlerContext ctx) { -// logger.info("EchoSocketServer handlerRemoved"); -// buff = null; -// } -// -// @Override -// public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { -// ctx.close(); -// cause.printStackTrace(); -// } -//} \ No newline at end of file +package com.eactive.httpmockserver.socket; + +import java.io.UnsupportedEncodingException; + +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + +@Component +@Sharable +public class EchoSocketServerHandler extends ChannelInboundHandlerAdapter { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private BytesMessageSpec spec; + + public EchoSocketServerHandler() { + } + + public EchoSocketServerHandler(BytesMessageSpec spec) { + this.spec = spec; + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) { + logger.info("EchoSocketServer handlerAdded"); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + logger.info("Remote Address: " + ctx.channel().remoteAddress().toString()); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + logger.info("EchoSocketServer channelRead"); + + try { + spec.setEncode(StringUtils.defaultIfBlank(spec.getEncode(), "euc-kr")); + String message = new String(ByteBufUtil.getBytes((ByteBuf) msg), spec.getEncode()); + logger.info("=================================================="); + logger.info("Received Message=" + message); + logger.info("=================================================="); + + // length + content + String responseMsg = assignResponseMessage(message); + logger.info("=================================================="); + logger.info("Response Message=" + responseMsg); + logger.info("=================================================="); + + // sleep Àû¿ë + if (spec.getSleepSeconds() != null) { + int sleepSeconds = spec.getSleepSeconds().intValue(); + if (sleepSeconds > 0) { + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("Start Sleep {} Seconds.", sleepSeconds); + logger.info("..."); + Thread.sleep(sleepSeconds * 1000l); + logger.info("......"); + logger.info("Finished Sleep {} Seconds.", sleepSeconds); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } + } + + ctx.write(Unpooled.wrappedBuffer(responseMsg.getBytes(spec.getEncode()))); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + + private String assignResponseMessage(String body) throws UnsupportedEncodingException { + int llFieldLength = (spec.getLlFieldLength() == null ? 8 : spec.getLlFieldLength().intValue()); + + if (StringUtils.isNotBlank(spec.getResponseBody())) { + return appendLengthField(StringUtils.substring(spec.getResponseBody(), llFieldLength), spec); + } + + if (spec.getEchoReplaceStringList() != null) { + byte[] bytes = body.getBytes(spec.getEncode()); + for (EchoReplaceString echoReplaceString : spec.getEchoReplaceStringList()) { + bytes = replaceString(bytes, echoReplaceString.getPosition().intValue(), + echoReplaceString.getReplaceString().getBytes(spec.getEncode()), llFieldLength); + } + + body = new String(bytes, spec.getEncode()); + } + + return appendLengthField(body, spec); + } + + private byte[] replaceString(byte[] bytes, int position, byte[] replaceBytes, int llFieldLength) { + int idx = position - llFieldLength; + if (idx < 0 || bytes.length < idx) { + logger.warn("//**//**//**//**//**//**//**//**//**//**//**//**//**//**//**//**"); + logger.warn("//**//**//**//**//**//**//**//**//**//**//**//**//**//**//**//**"); + logger.warn("invalid postion(MessageSize={}, postion={})", bytes.length + llFieldLength, position); + return bytes; + } + + if (bytes.length < idx + replaceBytes.length) { + byte[] newBytes = new byte[idx + replaceBytes.length]; + System.arraycopy(bytes, 0, newBytes, 0, idx); + System.arraycopy(replaceBytes, 0, newBytes, idx, replaceBytes.length); + return newBytes; + } + + System.arraycopy(replaceBytes, 0, bytes, idx, replaceBytes.length); + return bytes; + } + + public static String appendLengthField(String body, BytesMessageSpec spec) throws UnsupportedEncodingException { + int llFieldLength = (spec.getLlFieldLength() == null ? 8 : spec.getLlFieldLength().intValue()); + int length = body.getBytes(spec.getEncode()).length; + if (BooleanUtils.toBoolean(spec.getLlFieldLengthInclude())) { + length += llFieldLength; + } + return String.format("%0" + llFieldLength + "d%s", length, body); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + logger.info("EchoSocketServer channelReadComplete"); + ctx.flush(); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) { + logger.info("EchoSocketServer handlerRemoved"); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + ctx.close(); + cause.printStackTrace(); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/httpmockserver/socket/LengthHeaderFrameDecoder.java b/src/main/java/com/eactive/httpmockserver/socket/LengthHeaderFrameDecoder.java new file mode 100644 index 0000000..e6afdd3 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/socket/LengthHeaderFrameDecoder.java @@ -0,0 +1,55 @@ +package com.eactive.httpmockserver.socket; + +import java.util.List; + +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ReplayingDecoder; + +public class LengthHeaderFrameDecoder extends ReplayingDecoder { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private boolean readLength; + private int length; + private BytesMessageSpec spec; + + public LengthHeaderFrameDecoder() { + } + + public LengthHeaderFrameDecoder(BytesMessageSpec spec) { + this.spec = spec; + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List out) throws Exception { + int llFieldLength = (spec.getLlFieldLength() == null ? 8 : spec.getLlFieldLength().intValue()); + + if (!readLength) { + ByteBuf lengthFrame = buf.readBytes(llFieldLength); + length = assignMessageLength(ByteBufUtil.getBytes(lengthFrame)); + readLength = true; + logger.info("MessageLength = " + length); + checkpoint(); + } + + if (readLength) { + int contentLength = (BooleanUtils.toBoolean(spec.getLlFieldLengthInclude()) ? length - llFieldLength + : length); + ByteBuf frame = buf.readBytes(contentLength); + readLength = false; + checkpoint(); + out.add(frame); + } + } + + private int assignMessageLength(byte[] bytes) { + String lengthStr = new String(bytes); + return NumberUtils.toInt(lengthStr); + } +} diff --git a/src/main/java/com/eactive/httpmockserver/socket/SocketServerManageController.java b/src/main/java/com/eactive/httpmockserver/socket/SocketServerManageController.java index 0a2a7be..16d1557 100644 --- a/src/main/java/com/eactive/httpmockserver/socket/SocketServerManageController.java +++ b/src/main/java/com/eactive/httpmockserver/socket/SocketServerManageController.java @@ -1,45 +1,69 @@ -//package com.eactive.httpmockserver.socket; -// -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.stereotype.Controller; -//import org.springframework.web.bind.annotation.RequestMapping; -//import org.springframework.web.bind.annotation.ResponseBody; -// -//@Controller -//public class SocketServerManageController { -// private final Logger logger = LoggerFactory.getLogger(this.getClass()); -// -// @Autowired -// private EchoSocketServer echoSocketServer; -// -// @RequestMapping("/manage/socket/startEchoSocketServer") -// @ResponseBody -// public String startEchoServer() { -// logger.info("starting.."); -// -// new Thread(new Runnable() { -// @Override -// public void run() { -// try { -// echoSocketServer.start(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// }).start(); -// -// logger.info("started"); -// return "Success"; -// } -// -// @RequestMapping("/manage/socket/stopEchoSocketServer") -// @ResponseBody -// public String stopEchoServer() { -// logger.info("stopping.."); -// echoSocketServer.stop(); -// logger.info("stopped"); -// return "Success"; -// } -//} +package com.eactive.httpmockserver.socket; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.persistence.NoResultException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class SocketServerManageController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private BytesMessageSpecService specService; + + private EchoSocketServer echoSocketServer; + + @PostConstruct + public void start() { + logger.info("EchoSocketServer starting.."); + + BytesMessageSpec spec = specService.findActiveBytesMessageSpec(); + if (spec == null) { + logger.info("EchoSocketServer not started(No have rule)"); + return; + } + logger.info("BytesMessageSpec=" + spec.toString()); + + new Thread(new Runnable() { + @Override + public void run() { + try { + echoSocketServer = new EchoSocketServer(spec); + echoSocketServer.start(); + logger.info("EchoSocketServer started"); + } catch (NoResultException e) { + logger.info("EchoSocketServer not started(No have rule)"); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + }).start(); + } + + @PreDestroy + public void stop() { + logger.info("EchoSocketServer stopping.."); + + if (echoSocketServer != null) { + echoSocketServer.stop(); + } + + logger.info("EchoSocketServer stopped"); + } + + @RequestMapping("/manage/socket/restartEchoSocketServer") + @ResponseBody + public String restartEchoServer() { + stop(); + start(); + + return "Success"; + } +}