diff --git a/webinterface/build.gradle b/webinterface/build.gradle index d29c061..8b9c396 100644 --- a/webinterface/build.gradle +++ b/webinterface/build.gradle @@ -1,5 +1,5 @@ group = 'asys' -version = '0.15-SNAPSHOT' +version = '0.16-SNAPSHOT' buildscript { repositories { diff --git a/webinterface/src/main/java/asys/webinterface/Activator.java b/webinterface/src/main/java/asys/webinterface/Activator.java index f4c879d..3d52bf8 100644 --- a/webinterface/src/main/java/asys/webinterface/Activator.java +++ b/webinterface/src/main/java/asys/webinterface/Activator.java @@ -4,8 +4,6 @@ */ package asys.webinterface; -import asys.webinterface.api.HttpReqResp; -import asys.webinterface.api.WebModule; import asys.webinterface.api.Webinterface; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -13,8 +11,6 @@ import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; - public class Activator implements BundleActivator { private final Logger logger = LoggerFactory.getLogger(Activator.class); private ServiceRegistration serviceMainMenu; @@ -23,7 +19,7 @@ public class Activator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { WebinterfaceImpl webinterface = new WebinterfaceImpl(); - webinterface.addModule(createSelfModule()); + webinterface.addModule(new Modules_WebModule(context)); logger.trace("Register service: {}", Webinterface.class); serviceMainMenu = context.registerService(Webinterface.class, webinterface, null); @@ -32,36 +28,6 @@ public class Activator implements BundleActivator { webServer.start(8778); } - private WebModule createSelfModule() { - return new WebModule() { - @Override - public String getName() { - return "modules"; - } - - @Override - public List getStylesheetsLinks() { - return Collections.emptyList(); - } - - @Override - public List getJavaScriptLinks() { - return Collections.singletonList("/static/module.js"); - } - - @Override - public Map getMainMenuItems() { - return new HashMap(){{ - this.put("Модули", "/modules"); - }}; - } - - @Override - public void handle(HttpReqResp httpReqResp) { - } - }; - } - @Override public void stop(BundleContext context) throws Exception { webServer.stop(); diff --git a/webinterface/src/main/java/asys/webinterface/AjaxHandler.java b/webinterface/src/main/java/asys/webinterface/AjaxHandler.java deleted file mode 100644 index f9b0a65..0000000 --- a/webinterface/src/main/java/asys/webinterface/AjaxHandler.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * DmitriyMX - * 2016-12-13 - */ -package asys.webinterface; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; - -public class AjaxHandler implements HttpHandler { - private static final Charset defaultCharset = Charset.forName("UTF-8"); - private BundleContext context; - private int selfId; - - public AjaxHandler(BundleContext context) { - this.context = context; - selfId = (int) context.getBundle().getBundleId(); - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String outJson = "{}"; - - String jsonPath = httpExchange.getRequestURI().getPath(); - if (jsonPath.equals("/ajax/bundles.json")) { - - if (httpExchange.getRequestURI().getQuery() != null && !httpExchange.getRequestURI().getQuery().isEmpty()) { - Map query = queryToMap(httpExchange.getRequestURI().getQuery()); - if (query.containsKey("id")) { - Bundle bundle = context.getBundle(Integer.valueOf(query.get("id"))); - if (bundle == null) { - sendResponse(httpExchange, outJson); - return; - } - - if (query.containsKey("act") && query.get("act").equals("upd")) { - try { - bundle.update(); - } catch (BundleException e) { - e.printStackTrace(); - } - } - - outJson = bundleInfo(bundle).toString(); - } - } else { - outJson = bundleList().toString(); - } - } - - sendResponse(httpExchange, outJson); - } - - private void sendResponse(HttpExchange httpExchange, String outJson) throws IOException { - httpExchange.getResponseHeaders().add("Context-Type", "application/json;charset=utf-8"); - httpExchange.sendResponseHeaders(200, 0); - OutputStream responseBody = httpExchange.getResponseBody(); - responseBody.write(outJson.getBytes(defaultCharset)); - responseBody.close(); - } - - private JsonArray bundleList() { - JsonArray jsonArray = new JsonArray(); - - for (Bundle bundle : context.getBundle(0).getBundleContext().getBundles()) { - if (bundle.getBundleId() == 0 || bundle.getBundleId() == selfId) { - continue; - } - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("id", bundle.getBundleId()); - jsonObject.addProperty("state", bundle.getState()); - jsonObject.addProperty("name", bundle.getHeaders().get("Bundle-Name")); - jsonObject.addProperty("symname", bundle.getSymbolicName()); - jsonObject.addProperty("lastModified", bundle.getHeaders().get("Bnd-LastModified")); - jsonObject.addProperty("version", bundle.getVersion().toString()); - jsonArray.add(jsonObject); - } - - return jsonArray; - } - - private JsonObject bundleInfo(Bundle bundle) { - JsonObject jsonObject = new JsonObject(); - - if (bundle != null && bundle.getBundleId() != 0 && bundle.getBundleId() != selfId) { - jsonObject.addProperty("id", bundle.getBundleId()); - jsonObject.addProperty("state", bundle.getState()); - jsonObject.addProperty("name", bundle.getHeaders().get("Bundle-Name")); - jsonObject.addProperty("symname", bundle.getSymbolicName()); - jsonObject.addProperty("lastModified", bundle.getHeaders().get("Bnd-LastModified")); - jsonObject.addProperty("version", bundle.getVersion().toString()); - } - - return jsonObject; - } - - private Map queryToMap(String query){ - Map result = new HashMap<>(); - for (String param : query.split("&")) { - String pair[] = param.split("="); - if (pair.length>1) { - result.put(pair[0], pair[1]); - }else{ - result.put(pair[0], ""); - } - } - return result; - } -} diff --git a/webinterface/src/main/java/asys/webinterface/HttpReqRespImpl.java b/webinterface/src/main/java/asys/webinterface/HttpReqRespImpl.java deleted file mode 100644 index 5c30e46..0000000 --- a/webinterface/src/main/java/asys/webinterface/HttpReqRespImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * DmitriyMX - * 2017-03-15 - */ -package asys.webinterface; - -import asys.webinterface.api.HttpReqResp; -import com.sun.net.httpserver.HttpExchange; - -public class HttpReqRespImpl implements HttpReqResp { - private HttpExchange httpExchange; - - public HttpReqRespImpl(HttpExchange httpExchange) { - this.httpExchange = httpExchange; - } - - @Override - public String[] getRequestURIParts() { - String uriStr = httpExchange.getRequestURI().toString().replaceAll("/{2,}", "/"); - if (uriStr.startsWith("/")) { - uriStr = uriStr.replaceFirst("/",""); - } - - String[] result = uriStr.split("/"); - if (result.length == 1 && result[0].isEmpty()) { - return new String[0]; - } else { - return result; - } - } -} diff --git a/webinterface/src/main/java/asys/webinterface/IndexHandler.java b/webinterface/src/main/java/asys/webinterface/IndexHandler.java index e0c347c..822249d 100644 --- a/webinterface/src/main/java/asys/webinterface/IndexHandler.java +++ b/webinterface/src/main/java/asys/webinterface/IndexHandler.java @@ -4,7 +4,6 @@ */ package asys.webinterface; -import asys.webinterface.api.HttpReqResp; import asys.webinterface.api.WebModule; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; @@ -13,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; +import java.net.URI; import java.nio.charset.Charset; public class IndexHandler implements HttpHandler { @@ -20,12 +20,14 @@ public class IndexHandler implements HttpHandler { static final Charset defaultCharset = Charset.forName("UTF-8"); private String htmlTemplate; private WebinterfaceImpl webinterface; + private WebModule modulesWM; public IndexHandler(WebinterfaceImpl webinterface) { try { InputStream inputStream = getClass().getResourceAsStream("/index.html"); htmlTemplate = IOUtils.toString(inputStream, "UTF-8"); this.webinterface = webinterface; + this.modulesWM = webinterface.getModule("modules"); } catch (Exception e) { throw new RuntimeException("Error load htmlTemplate", e); } @@ -33,25 +35,27 @@ public class IndexHandler implements HttpHandler { @Override public void handle(HttpExchange httpExchange) throws IOException { - HttpReqResp httpReqResp = new HttpReqRespImpl(httpExchange); - String[] requestURIParts = httpReqResp.getRequestURIParts(); - if (requestURIParts.length > 0 && requestURIParts[0].equals("module")) { - logger.debug("Module request: {}", requestURIParts[1]); - WebModule module = webinterface.getModule(requestURIParts[1]); + String[] requestURIParts = getRequestURIParts(httpExchange.getRequestURI()); + if (requestURIParts.length > 0) { + logger.debug("Module request: {}", requestURIParts[0]); + WebModule module = webinterface.getModule(requestURIParts[0]); if (module != null) { - sendHtmlTemplate(prepareHtmlTemplate(module), httpExchange); + if (!module.handle(httpExchange)) { + sendHtmlTemplate(prepareHtmlTemplate(module), httpExchange); + } } else { - logger.warn("404 - module \"{}\" not found", requestURIParts[1]); + logger.warn("404 - module \"{}\" not found", requestURIParts[0]); } - } else if (requestURIParts.length == 0 || requestURIParts[0].equals("modules")) { + } else { logger.debug("use default module"); - sendHtmlTemplate(prepareHtmlTemplate(webinterface.getModule("modules")), httpExchange); + if (!modulesWM.handle(httpExchange)) { + sendHtmlTemplate(prepareHtmlTemplate(modulesWM), httpExchange); + } } } private byte[] prepareHtmlTemplate(WebModule module) { - return htmlTemplate.replace("<{moduleScript}>", webinterface.javascriptToTags(module)) - .replace("<{moduleStylesheet}>", webinterface.stylesheetToTags(module)).getBytes(defaultCharset); + return htmlTemplate.replace("<{moduleScript}>", webinterface.javascriptToTags(module)).getBytes(defaultCharset); } private void sendHtmlTemplate(byte[] htmlTemplateBytes, HttpExchange httpExchange) throws IOException { @@ -61,4 +65,18 @@ public class IndexHandler implements HttpHandler { responseBody.write(htmlTemplateBytes); responseBody.close(); } + + private String[] getRequestURIParts(URI uri) { + String uriStr = uri.toString().replaceAll("/{2,}", "/"); + if (uriStr.startsWith("/")) { + uriStr = uriStr.replaceFirst("/",""); + } + + String[] result = uriStr.split("/"); + if (result.length == 1 && result[0].isEmpty()) { + return new String[0]; + } else { + return result; + } + } } diff --git a/webinterface/src/main/java/asys/webinterface/Modules_WebModule.java b/webinterface/src/main/java/asys/webinterface/Modules_WebModule.java new file mode 100644 index 0000000..7553b40 --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/Modules_WebModule.java @@ -0,0 +1,127 @@ +/* + * DmitriyMX + * 2017-03-18 + */ +package asys.webinterface; + +import asys.webinterface.api.WebModule; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.sun.net.httpserver.HttpExchange; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +public class Modules_WebModule extends WebModule{ + private final Logger logger = LoggerFactory.getLogger(Modules_WebModule.class); + private BundleContext context; + private int selfId; + private final String EMPTY_JSON = "{}"; + + public Modules_WebModule(BundleContext context) { + this.context = context; + this.selfId = (int) context.getBundle().getBundleId(); + } + + @Override + public String getName() { + return "modules"; + } + + @Override + public String getReactJSModuleLink() { + return "/modules/module.js"; + } + + @Override + public Map getMainMenuItems() { + return new HashMap(){{ + this.put("Модули", "/modules"); + }}; + } + + @Override + public boolean handle(HttpExchange httpExchange) throws IOException { + String urlPath = httpExchange.getRequestURI().getPath(); + if (urlPath.equals("/modules/ajax/bundles.json")) { + if (httpExchange.getRequestURI().getQuery() != null && + !httpExchange.getRequestURI().getQuery().isEmpty()) { + this.sendBundleInfo(httpExchange); + return true; + } else { + this.sendJson(httpExchange, bundleList()); + return true; + } + } else if (urlPath.equals("/modules/module.js")) { + InputStream stream = getClass().getResourceAsStream("/static/module.js"); + httpExchange.getResponseHeaders().add("Content-Type", "text/javascript;charset=utf-8"); + this.sendContent(httpExchange, 0, stream); + return true; + } + return false; + } + + private void sendBundleInfo(HttpExchange httpExchange) throws IOException { + Map query = this.queryToMap(httpExchange.getRequestURI().getQuery()); + if (query.containsKey("id")) { + Bundle bundle = context.getBundle(Integer.valueOf(query.get("id"))); + if (bundle == null) { + this.sendJson(httpExchange, EMPTY_JSON); + return; + } + + if (query.containsKey("act") && query.get("act").equals("upd")) { + try { + bundle.update(); + } catch (BundleException e) { + logger.error("Bundle update", e); + } + + this.sendJson(httpExchange, bundleInfo(bundle)); + } + } + } + + private JsonObject bundleInfo(Bundle bundle) { + JsonObject jsonObject = new JsonObject(); + + if (bundle != null && bundle.getBundleId() != 0 && bundle.getBundleId() != selfId) { + jsonObject.addProperty("id", bundle.getBundleId()); + jsonObject.addProperty("state", bundle.getState()); + jsonObject.addProperty("name", bundle.getHeaders().get("Bundle-Name")); + jsonObject.addProperty("symname", bundle.getSymbolicName()); + jsonObject.addProperty("lastModified", bundle.getHeaders().get("Bnd-LastModified")); + jsonObject.addProperty("version", bundle.getVersion().toString()); + } + + return jsonObject; + } + + private JsonArray bundleList() { + JsonArray jsonArray = new JsonArray(); + + for (Bundle bundle : context.getBundle(0).getBundleContext().getBundles()) { + if (bundle.getBundleId() == 0 || bundle.getBundleId() == selfId) { + continue; + } + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", bundle.getBundleId()); + jsonObject.addProperty("state", bundle.getState()); + jsonObject.addProperty("name", bundle.getHeaders().get("Bundle-Name")); + jsonObject.addProperty("symname", bundle.getSymbolicName()); + jsonObject.addProperty("lastModified", bundle.getHeaders().get("Bnd-LastModified")); + jsonObject.addProperty("version", bundle.getVersion().toString()); + jsonArray.add(jsonObject); + } + + return jsonArray; + } + +} diff --git a/webinterface/src/main/java/asys/webinterface/WebServer.java b/webinterface/src/main/java/asys/webinterface/WebServer.java index bf69e44..cddaeb8 100644 --- a/webinterface/src/main/java/asys/webinterface/WebServer.java +++ b/webinterface/src/main/java/asys/webinterface/WebServer.java @@ -25,7 +25,6 @@ public class WebServer { server.createContext("/", new IndexHandler(webinterface)); server.createContext("/app.js", new AppJsHandler(webinterface)); server.createContext("/static", new StaticHandler()); - server.createContext("/ajax", new AjaxHandler(context)); server.start(); } diff --git a/webinterface/src/main/java/asys/webinterface/WebinterfaceImpl.java b/webinterface/src/main/java/asys/webinterface/WebinterfaceImpl.java index d3fc4a8..b2ea90a 100644 --- a/webinterface/src/main/java/asys/webinterface/WebinterfaceImpl.java +++ b/webinterface/src/main/java/asys/webinterface/WebinterfaceImpl.java @@ -43,22 +43,6 @@ public class WebinterfaceImpl implements Webinterface { } public String javascriptToTags(WebModule webModule) { - StringJoiner sj = new StringJoiner("\n"); - - for (String link : webModule.getJavaScriptLinks()) { - sj.add(String.format("", link)); - } - - return sj.toString(); - } - - public String stylesheetToTags(WebModule webModule) { - StringJoiner sj = new StringJoiner("\n"); - - for (String link : webModule.getJavaScriptLinks()) { - sj.add(String.format("", link)); - } - - return sj.toString(); + return String.format("", webModule.getReactJSModuleLink()); } } diff --git a/webinterface/src/main/java/asys/webinterface/api/HttpReqResp.java b/webinterface/src/main/java/asys/webinterface/api/HttpReqResp.java deleted file mode 100644 index a88b6ac..0000000 --- a/webinterface/src/main/java/asys/webinterface/api/HttpReqResp.java +++ /dev/null @@ -1,9 +0,0 @@ -/* - * DmitriyMX - * 2017-03-15 - */ -package asys.webinterface.api; - -public interface HttpReqResp { - String[] getRequestURIParts(); -} diff --git a/webinterface/src/main/java/asys/webinterface/api/WebModule.java b/webinterface/src/main/java/asys/webinterface/api/WebModule.java index 9c8c315..9b07c2d 100644 --- a/webinterface/src/main/java/asys/webinterface/api/WebModule.java +++ b/webinterface/src/main/java/asys/webinterface/api/WebModule.java @@ -4,13 +4,73 @@ */ package asys.webinterface.api; +import com.google.gson.JsonElement; +import com.sun.net.httpserver.HttpExchange; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.util.HashMap; import java.util.List; import java.util.Map; -public interface WebModule { - String getName(); - List getStylesheetsLinks(); - List getJavaScriptLinks(); - Map getMainMenuItems(); - void handle(HttpReqResp httpReqResp); +public abstract class WebModule { + public abstract String getName(); + public abstract String getReactJSModuleLink(); + public abstract Map getMainMenuItems(); + + /** + * Обработчик входящих данных + * @param httpExchange запрос от клиента + * @return true, если модуль самостоятельно отправил данные клиенту + */ + public abstract boolean handle(HttpExchange httpExchange) throws IOException; + + protected void sendHttpCode(HttpExchange httpExchange, int code, String message) throws IOException { + byte[] bytes = message.getBytes("UTF-8"); + httpExchange.sendResponseHeaders(code, bytes.length); + OutputStream outputStream = httpExchange.getResponseBody(); + outputStream.write(bytes); + outputStream.flush(); + outputStream.close(); + } + + protected void sendJson(HttpExchange httpExchange, JsonElement jsonElement) throws IOException { + sendJson(httpExchange, jsonElement.toString()); + } + + protected void sendJson(HttpExchange httpExchange, String jsonStr) throws IOException { + httpExchange.getResponseHeaders().add("Context-Type", "application/json;charset=utf-8"); + sendContent(httpExchange, jsonStr); + } + + protected void sendContent(HttpExchange httpExchange, String content) throws IOException { + byte[] bytes = content.getBytes("UTF-8"); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + sendContent(httpExchange, bytes.length, bais); + } + + protected void sendContent(HttpExchange httpExchange, long sizeContent, InputStream stream) throws IOException { + List listValues = httpExchange.getResponseHeaders().get("Context-Type"); + if (listValues == null || listValues.isEmpty()) { + httpExchange.getResponseHeaders().add("Context-Type", "application/octet-stream"); + } + + httpExchange.sendResponseHeaders(200, sizeContent); + OutputStream responseBody = httpExchange.getResponseBody(); + IOUtils.copy(stream, responseBody); + responseBody.close(); + } + + protected Map queryToMap(String query){ + Map result = new HashMap<>(); + for (String param : query.split("&")) { + String pair[] = param.split("="); + if (pair.length>1) { + result.put(pair[0], pair[1]); + }else{ + result.put(pair[0], ""); + } + } + return result; + } } diff --git a/webinterface/src/main/resources/index.html b/webinterface/src/main/resources/index.html index 6831f04..28d8faa 100644 --- a/webinterface/src/main/resources/index.html +++ b/webinterface/src/main/resources/index.html @@ -9,7 +9,6 @@ background: url('/static/background.png') fixed; } - <{moduleStylesheet}> diff --git a/webinterface/src/main/resources/static/module.js b/webinterface/src/main/resources/static/module.js index ab70c03..da693a4 100644 --- a/webinterface/src/main/resources/static/module.js +++ b/webinterface/src/main/resources/static/module.js @@ -34,7 +34,7 @@ var BundleTableRow = React.createClass({ }, bndUpd: function() { var _this = this; - fetch('/ajax/bundles.json?id='+this.props.id+'&act=upd') + fetch('/modules/ajax/bundles.json?id='+this.props.id+'&act=upd') .then(function(resp){ resp.json().then(function(data){ _this.setState({ @@ -74,7 +74,7 @@ var ContentModule = React.createClass({ }}, requestBundleList: function() { var _this = this; - fetch('/ajax/bundles.json') + fetch('/modules/ajax/bundles.json') .then(function(response){ response.json().then(function(data){ console.debug(data);