| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- package com.mes.util;
- import com.alibaba.fastjson2.JSONObject;
- import com.github.xingshuangs.iot.protocol.melsec.enums.EMcFrameType;
- import com.github.xingshuangs.iot.protocol.melsec.enums.EMcSeries;
- import com.github.xingshuangs.iot.protocol.melsec.service.McPLC;
- import com.sun.net.httpserver.HttpExchange;
- import com.sun.net.httpserver.HttpHandler;
- import com.sun.net.httpserver.HttpServer;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.io.OutputStream;
- import java.net.InetSocketAddress;
- import java.net.URI;
- import java.net.URLDecoder;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Properties;
- import java.util.concurrent.Executors;
- public class PlcProxyServer {
- private static final Logger log = LoggerFactory.getLogger(PlcProxyServer.class);
- private static final int DEFAULT_PORT = 18080;
- private static final int DEFAULT_CONNECT_TIMEOUT_MS = 2000;
- private static final int DEFAULT_RECEIVE_TIMEOUT_MS = 3000;
- private static final Map<String, Object> PLC_LOCKS = new HashMap<>();
- private static final Map<String, McPLC> PLC_CACHE = new HashMap<>();
- public static void main(String[] args) throws Exception {
- Properties props = ConfigUtils.loadPropertiesUnchecked();
- PlcTarget.setProperties(props);
- int port = parseInt(props.getProperty("plc.proxy.server.port"), DEFAULT_PORT);
- HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
- server.createContext("/health", new HealthHandler());
- server.createContext("/readBoolean", new ReadBooleanHandler());
- server.createContext("/readBooleans", new ReadBooleansHandler());
- server.createContext("/readInt16", new ReadInt16Handler());
- server.createContext("/writeBoolean", new WriteBooleanHandler());
- server.setExecutor(Executors.newCachedThreadPool());
- server.start();
- log.info("PLC proxy server started, port={}", port);
- System.out.println("PLC proxy server started, port=" + port);
- }
- private static class HealthHandler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) {
- JSONObject json = ok();
- json.put("status", "UP");
- writeJson(exchange, 200, json);
- }
- }
- private static class ReadBooleanHandler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) {
- handlePlc(exchange, new PlcAction() {
- @Override
- public Object execute(McPLC plc, Map<String, String> params) {
- return plc.readBoolean(required(params, "address"));
- }
- });
- }
- }
- private static class ReadBooleansHandler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) {
- handlePlc(exchange, new PlcAction() {
- @Override
- public Object execute(McPLC plc, Map<String, String> params) {
- int count = parseInt(params.get("count"), 1);
- return plc.readBoolean(required(params, "address"), count);
- }
- });
- }
- }
- private static class ReadInt16Handler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) {
- handlePlc(exchange, new PlcAction() {
- @Override
- public Object execute(McPLC plc, Map<String, String> params) {
- return plc.readInt16(required(params, "address"));
- }
- });
- }
- }
- private static class WriteBooleanHandler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) {
- handlePlc(exchange, new PlcAction() {
- @Override
- public Object execute(McPLC plc, Map<String, String> params) {
- boolean value = Boolean.parseBoolean(required(params, "value"));
- plc.writeBoolean(required(params, "address"), value);
- return Boolean.valueOf(value);
- }
- });
- }
- }
- private static void handlePlc(HttpExchange exchange, PlcAction action) {
- Map<String, String> params = parseQuery(exchange.getRequestURI());
- try {
- PlcTarget target = PlcTarget.from(params);
- Object result;
- synchronized (getPlcLock(target.key)) {
- McPLC plc = getCachedPlc(target);
- try {
- result = action.execute(plc, params);
- } catch (RuntimeException e) {
- discardCachedPlc(target.key, plc);
- throw e;
- }
- }
- JSONObject json = ok();
- json.put("value", result);
- writeJson(exchange, 200, json);
- } catch (Exception e) {
- log.warn("PLC proxy request failed, uri={}", exchange.getRequestURI(), e);
- JSONObject json = new JSONObject();
- json.put("success", false);
- json.put("message", e.getMessage());
- writeJson(exchange, 500, json);
- }
- }
- private static McPLC getCachedPlc(PlcTarget target) {
- McPLC plc = PLC_CACHE.get(target.key);
- if (plc == null) {
- plc = createPlc(target);
- PLC_CACHE.put(target.key, plc);
- log.info("PLC proxy connected, plc={}, series={}, frame={}", target.key, target.series, target.frame);
- }
- return plc;
- }
- private static McPLC createPlc(PlcTarget target) {
- EMcSeries series = parseSeries(target.series);
- EMcFrameType frameType = parseFrameType(target.frame, series.getFrameType());
- McPLC plc = new McPLC(series, frameType, target.ip, target.port);
- plc.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT_MS);
- plc.setReceiveTimeout(DEFAULT_RECEIVE_TIMEOUT_MS);
- return plc;
- }
- private static void discardCachedPlc(String key, McPLC plc) {
- McPLC cached = PLC_CACHE.get(key);
- if (cached == plc) {
- PLC_CACHE.remove(key);
- }
- if (plc != null) {
- plc.close();
- }
- }
- private static Object getPlcLock(String key) {
- synchronized (PLC_LOCKS) {
- Object lock = PLC_LOCKS.get(key);
- if (lock == null) {
- lock = new Object();
- PLC_LOCKS.put(key, lock);
- }
- return lock;
- }
- }
- private static JSONObject ok() {
- JSONObject json = new JSONObject();
- json.put("success", true);
- return json;
- }
- private static void writeJson(HttpExchange exchange, int status, JSONObject json) {
- byte[] body = json.toJSONString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
- try {
- exchange.getResponseHeaders().set("Content-Type", "application/json;charset=UTF-8");
- exchange.sendResponseHeaders(status, body.length);
- try (OutputStream os = exchange.getResponseBody()) {
- os.write(body);
- }
- } catch (Exception e) {
- log.warn("write proxy response failed", e);
- } finally {
- exchange.close();
- }
- }
- private static Map<String, String> parseQuery(URI uri) {
- Map<String, String> params = new HashMap<>();
- String query = uri.getRawQuery();
- if (query == null || query.isEmpty()) {
- return params;
- }
- String[] pairs = query.split("&");
- for (String pair : pairs) {
- int index = pair.indexOf('=');
- String key = index >= 0 ? pair.substring(0, index) : pair;
- String value = index >= 0 ? pair.substring(index + 1) : "";
- params.put(decode(key), decode(value));
- }
- return params;
- }
- private static String required(Map<String, String> params, String key) {
- String value = params.get(key);
- if (value == null || value.trim().isEmpty()) {
- throw new IllegalArgumentException("missing parameter: " + key);
- }
- return value;
- }
- private static String decode(String value) {
- try {
- return URLDecoder.decode(value, "UTF-8");
- } catch (Exception e) {
- return value;
- }
- }
- private static EMcSeries parseSeries(String series) {
- if ("Q_L".equalsIgnoreCase(series)) {
- return EMcSeries.Q_L;
- }
- if ("IQ_R".equalsIgnoreCase(series)) {
- return EMcSeries.IQ_R;
- }
- return EMcSeries.QnA;
- }
- private static EMcFrameType parseFrameType(String frameType, EMcFrameType defaultValue) {
- if (frameType == null || frameType.trim().isEmpty()) {
- return defaultValue;
- }
- String normalized = frameType.trim().toUpperCase(Locale.ROOT);
- if (!normalized.startsWith("FRAME_")) {
- normalized = "FRAME_" + normalized;
- }
- try {
- return EMcFrameType.valueOf(normalized);
- } catch (Exception e) {
- return defaultValue;
- }
- }
- private static int parseInt(String value, int defaultValue) {
- try {
- return Integer.parseInt(value);
- } catch (Exception e) {
- return defaultValue;
- }
- }
- private interface PlcAction {
- Object execute(McPLC plc, Map<String, String> params);
- }
- private static class PlcTarget {
- private static Properties properties = new Properties();
- private final String key;
- private final String ip;
- private final int port;
- private final String series;
- private final String frame;
- private PlcTarget(String ip, int port, String series, String frame) {
- this.ip = ip;
- this.port = port;
- this.series = firstNotEmpty(series, findConfiguredValue(ip, port, "plc.series"));
- this.frame = firstNotEmpty(frame, findConfiguredValue(ip, port, "plc.frame"));
- this.key = ip + ":" + port;
- }
- private static void setProperties(Properties props) {
- properties = props == null ? new Properties() : props;
- }
- private static PlcTarget from(Map<String, String> params) {
- String plc = required(params, "plc");
- int index = plc.lastIndexOf(':');
- if (index <= 0 || index == plc.length() - 1) {
- throw new IllegalArgumentException("invalid plc parameter: " + plc);
- }
- String ip = plc.substring(0, index);
- int port = parseInt(plc.substring(index + 1), 0);
- if (port <= 0) {
- throw new IllegalArgumentException("invalid plc port: " + plc);
- }
- return new PlcTarget(ip, port, params.get("series"), params.get("frame"));
- }
- private static String findConfiguredValue(String ip, int port, String suffix) {
- for (Object keyObj : properties.keySet()) {
- String key = String.valueOf(keyObj);
- if (!key.endsWith(".plc.ip")) {
- continue;
- }
- String prefix = key.substring(0, key.length() - ".plc.ip".length());
- String configuredIp = properties.getProperty(prefix + ".plc.ip");
- int configuredPort = parseInt(properties.getProperty(prefix + ".plc.port"), 0);
- if (ip.equals(configuredIp) && port == configuredPort) {
- return properties.getProperty(prefix + "." + suffix);
- }
- }
- return "";
- }
- private static String firstNotEmpty(String first, String second) {
- if (first != null && !first.trim().isEmpty()) {
- return first;
- }
- return second == null ? "" : second;
- }
- }
- }
|