From 003f90160b7bfd7f7872dcd4a62cc63f3447ab21 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Tue, 7 Mar 2017 01:19:40 +0300 Subject: [PATCH] Web interface --- settings.gradle | 3 +- webinterface/build.gradle | 37 ++++++ .../java/asys/webinterface/Activator.java | 23 ++++ .../java/asys/webinterface/AjaxHandler.java | 120 ++++++++++++++++++ .../java/asys/webinterface/IndexHandler.java | 45 +++++++ .../java/asys/webinterface/StaticHandler.java | 41 ++++++ .../java/asys/webinterface/WebServer.java | 32 +++++ webinterface/src/main/resources/index.html | 14 ++ webinterface/src/main/resources/static/app.js | 51 ++++++++ 9 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 webinterface/build.gradle create mode 100644 webinterface/src/main/java/asys/webinterface/Activator.java create mode 100644 webinterface/src/main/java/asys/webinterface/AjaxHandler.java create mode 100644 webinterface/src/main/java/asys/webinterface/IndexHandler.java create mode 100644 webinterface/src/main/java/asys/webinterface/StaticHandler.java create mode 100644 webinterface/src/main/java/asys/webinterface/WebServer.java create mode 100644 webinterface/src/main/resources/index.html create mode 100644 webinterface/src/main/resources/static/app.js diff --git a/settings.gradle b/settings.gradle index 28cf1d0..0d98748 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ rootProject.name = 'asys' include 'core' -include 'commons' \ No newline at end of file +include 'commons' +include 'webinterface' \ No newline at end of file diff --git a/webinterface/build.gradle b/webinterface/build.gradle new file mode 100644 index 0000000..a4f3d78 --- /dev/null +++ b/webinterface/build.gradle @@ -0,0 +1,37 @@ +group = 'asys' +version = '0.8-SNAPSHOT' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath "org.dm.gradle:gradle-bundle-plugin:0.10.0" + } +} + +apply plugin: 'org.dm.bundle' + +configurations { + included + compile.extendsFrom included +} + +jar { + dependsOn configurations.included + from { configurations.included.collect { it.isDirectory() ? it : zipTree(it).matching{exclude{it.path.contains('META-INF')} } } } +} + +bundle { + instructions << [ + 'Bundle-Name': 'ASys Web interface', + 'Bundle-Activator': 'asys.webinterface.Activator', + 'Import-Package': '*' + ] + exclude group: 'com.google.code.gson' +} + +dependencies { + compile project(':core') + included group: 'com.google.code.gson', name: 'gson', version: '2.7' +} \ No newline at end of file diff --git a/webinterface/src/main/java/asys/webinterface/Activator.java b/webinterface/src/main/java/asys/webinterface/Activator.java new file mode 100644 index 0000000..41a914a --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/Activator.java @@ -0,0 +1,23 @@ +/* + * DmitriyMX + * 2016-12-05 + */ +package asys.webinterface; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + private WebServer webServer; + + @Override + public void start(BundleContext context) throws Exception { + webServer = new WebServer(context); + webServer.start(8778); + } + + @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 new file mode 100644 index 0000000..f9b0a65 --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/AjaxHandler.java @@ -0,0 +1,120 @@ +/* + * 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/IndexHandler.java b/webinterface/src/main/java/asys/webinterface/IndexHandler.java new file mode 100644 index 0000000..3bc8191 --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/IndexHandler.java @@ -0,0 +1,45 @@ +/* + * DmitriyMX + * 2016-12-05 + */ +package asys.webinterface; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import org.osgi.framework.BundleContext; + +import java.io.*; +import java.nio.charset.Charset; + +public class IndexHandler implements HttpHandler { + private static final Charset defaultCharset = Charset.forName("UTF-8"); + private BundleContext context; + private String htmlTemplate; + + public IndexHandler(BundleContext context) { + this.context = context; + + try { + InputStream inputStream = getClass().getResourceAsStream("/index.html"); + BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append("\n"); + } + htmlTemplate = sb.toString(); + } catch (Exception e) { + throw new RuntimeException("Error load htmlTemplate", e); + } + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + httpExchange.getResponseHeaders().add("Context-Type","text/html;charset=utf-8"); + httpExchange.sendResponseHeaders(200, htmlTemplate.length()); + OutputStream responseBody = httpExchange.getResponseBody(); + responseBody.write(htmlTemplate.getBytes(defaultCharset)); + responseBody.close(); + } +} diff --git a/webinterface/src/main/java/asys/webinterface/StaticHandler.java b/webinterface/src/main/java/asys/webinterface/StaticHandler.java new file mode 100644 index 0000000..092f5a4 --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/StaticHandler.java @@ -0,0 +1,41 @@ +/* + * DmitriyMX + * 2016-12-12 + */ +package asys.webinterface; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class StaticHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String fileId = httpExchange.getRequestURI().getPath(); + fileId = fileId.replace("../", "").replace("//", "/"); + System.err.println(fileId); + InputStream inputStream = getClass().getResourceAsStream(fileId); + if (inputStream == null) { + String response = "Error 404 File not found."; + httpExchange.sendResponseHeaders(404, response.length()); + OutputStream outputStream = httpExchange.getResponseBody(); + outputStream.write(response.getBytes()); + outputStream.flush(); + outputStream.close(); + } else { + httpExchange.sendResponseHeaders(200, 0); + OutputStream outputStream = httpExchange.getResponseBody(); + final byte[] buffer = new byte[0x10000]; + int len; + while((len = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, len); + } + outputStream.flush(); + outputStream.close(); + inputStream.close(); + } + } +} diff --git a/webinterface/src/main/java/asys/webinterface/WebServer.java b/webinterface/src/main/java/asys/webinterface/WebServer.java new file mode 100644 index 0000000..5f77bdb --- /dev/null +++ b/webinterface/src/main/java/asys/webinterface/WebServer.java @@ -0,0 +1,32 @@ +/* + * DmitriyMX + * 2016-12-05 + */ +package asys.webinterface; + +import com.sun.net.httpserver.HttpServer; +import org.osgi.framework.BundleContext; + +import java.io.IOException; +import java.net.InetSocketAddress; + +public class WebServer { + private HttpServer server; + private BundleContext context; + + public WebServer(BundleContext context) { + this.context = context; + } + + public void start(int port) throws IOException { + server = HttpServer.create(new InetSocketAddress(port), 0); + server.createContext("/", new IndexHandler(context)); + server.createContext("/static", new StaticHandler()); + server.createContext("/ajax", new AjaxHandler(context)); + server.start(); + } + + public void stop() { + server.stop(0); + } +} diff --git a/webinterface/src/main/resources/index.html b/webinterface/src/main/resources/index.html new file mode 100644 index 0000000..914f2dd --- /dev/null +++ b/webinterface/src/main/resources/index.html @@ -0,0 +1,14 @@ + + + + + ASys: Web interface + + + + +

ASys: Web interface

+
+ + + \ No newline at end of file diff --git a/webinterface/src/main/resources/static/app.js b/webinterface/src/main/resources/static/app.js new file mode 100644 index 0000000..a83812c --- /dev/null +++ b/webinterface/src/main/resources/static/app.js @@ -0,0 +1,51 @@ +var app = angular.module('asysApp', []); + +// filtres +app.filter('stateFormat', function() { + return function(state) { + if (state == 1) {return 'UNINSTALLED';} + else if (state == 2) {return 'INSTALLED';} + else if (state == 4) {return 'RESOLVED';} + else if (state == 8) {return 'STARTING';} + else if (state == 16) {return 'STOPPING';} + else if (state == 32) {return 'ACTIVE';} + else {return 'UNKNOW('+state+')'} + } +}); + +/* --- [bundle-list] --- */ +app.component('bundleList', { + template: + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
IDNameStateVersionLast modifiedCTRL
{{bundle.id}}{{bundle.name}}{{bundle.state | stateFormat}}{{bundle.version}}{{bundle.lastModified | date:"dd/MM/yyyy HH:mm"}}
', + controller: function BundleListController($http) { + var self = this; + $http.get('/ajax/bundles.json').then(function(response) { + self.bundles = response.data; + }); + + this.bndUpd = function(bundleId){ + $http.get('/ajax/bundles.json?id='+bundleId+'&act=upd').then(function(response){ + for(var i=0; i < self.bundles.length; i++) { + if (self.bundles[i].id == bundleId) { + self.bundles[i] = response.data; + break; + } + } + }); + }; + } +}); \ No newline at end of file