/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.thingml.networkplugins.js; import com.eclipsesource.json.JsonObject; import org.apache.commons.io.IOUtils; import org.eclipse.emf.ecore.util.EcoreUtil; import org.sintef.thingml.*; import org.sintef.thingml.helpers.AnnotatedElementHelper; import org.thingml.compilers.Context; import org.thingml.compilers.spi.NetworkPlugin; import org.thingml.compilers.spi.SerializationPlugin; import java.io.*; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class JsUDPPlugin extends NetworkPlugin { public JsUDPPlugin() { super(); } public String getPluginID() { return "JsWSPlugin"; } public List<String> getSupportedProtocols() { List<String> res = new ArrayList<>(); res.add("UDP"); res.add("udp"); return res; } public List<String> getTargetedLanguages() { List<String> res = new ArrayList<>(); res.add("nodejs"); return res; } final Set<Message> messages = new HashSet<Message>(); private void clearMessages() { messages.clear(); } private void addMessage(Message m) { boolean contains = false; for(Message msg : messages) { if (EcoreUtil.equals(msg, m)) { contains = true; break; } } if (!contains) { messages.add(m); } } public void generateNetworkLibrary(Configuration cfg, Context ctx, Set<Protocol> protocols) { System.out.println("generateNetworkLibrary " + cfg.getName() + ", " + protocols.size()); StringBuilder builder; for (Protocol prot : protocols) { SerializationPlugin sp; try { sp = ctx.getSerializationPlugin(prot); } catch (UnsupportedEncodingException uee) { System.err.println("Could not get serialization plugin... Expect some errors in the generated code"); uee.printStackTrace(); return; } String serializers = ""; messages.clear(); for (ThingPortMessage tpm : getMessagesSent(cfg, prot)) { addMessage(tpm.m); } for(Message m : messages) { StringBuilder temp = new StringBuilder(); serializers += sp.generateSerialization(temp, prot.getName() + "BinaryProtocol", m); } builder = new StringBuilder(); messages.clear(); for (ThingPortMessage tpm : getMessagesReceived(cfg, prot)) { addMessage(tpm.m); } sp.generateParserBody(builder, prot.getName() + "BinaryProtocol", null, messages, null); final String result = builder.toString().replace("/*$SERIALIZERS$*/", serializers); try { final File f = new File(ctx.getOutputDirectory() + "/" + prot.getName() + "BinaryProtocol.js"); final OutputStream output = new FileOutputStream(f); IOUtils.write(result, output, Charset.forName("UTF-8")); IOUtils.closeQuietly(output); } catch (Exception e) { e.printStackTrace(); } new WSProtocol(ctx, prot, cfg).generate(); } } private class WSProtocol { Context ctx; Protocol prot; Configuration cfg; private List<Port> ports = new ArrayList<Port>(); public WSProtocol(Context ctx, Protocol prot, Configuration cfg) { this.ctx = ctx; this.prot = prot; this.cfg = cfg; } private void addPort(Port p) { boolean contains = false; for (Port port : ports) { if (EcoreUtil.equals(port, p)) { contains = true; break; } } if (!contains) { ports.add(p); } } public void generate() { for (ThingPortMessage tpm : getMessagesSent(cfg, prot)) { addPort(tpm.p); } for (ThingPortMessage tpm : getMessagesReceived(cfg, prot)) { addPort(tpm.p); } String template = ctx.getTemplateByID("templates/JsUDPPlugin.js"); template = template.replace("/*$FORMAT$*/", prot.getName() + "BinaryProtocol"); template = template.replace("/*$NAME$*/", prot.getName()); for (ExternalConnector conn : getExternalConnectors(cfg, prot)) { updateMain(ctx, cfg, conn); } for(Port p : ports) { StringBuilder builder = new StringBuilder(); builder.append("msg._port = '" + p.getName() + "';\n"); builder.append("instance._receive(msg);\n"); template = template.replace("/*$DISPATCH$*/", "/*$DISPATCH$*/\n" + builder.toString()); } StringBuilder builder = new StringBuilder(); for (Port p : ports) { for (Message m : p.getSends()) { builder.append(prot.getName() + ".prototype.receive" + m.getName() + "On" + p.getName() + " = function("); int i = 0; for (Parameter pa : m.getParameters()) { if (i > 0) builder.append(", "); builder.append(ctx.protectKeyword(pa.getName())); i++; } builder.append(") {\n"); builder.append("this.server.send(this.formatter." + m.getName() + "ToFormat("); i = 0; for (Parameter pa : m.getParameters()) { if (i > 0) builder.append(", "); builder.append(ctx.protectKeyword(pa.getName())); i++; } builder.append("));\n"); builder.append("};\n\n"); } } template = template.replace("/*$RECEIVERS$*/", "/*$RECEIVERS$*/\n" + builder.toString()); try { final File f = new File(ctx.getOutputDirectory() + "/UDPJS.js"); final OutputStream output = new FileOutputStream(f); IOUtils.write(template, output, Charset.forName("UTF-8")); IOUtils.closeQuietly(output); } catch (Exception e) { e.printStackTrace(); } } private void updateMain(Context ctx, Configuration cfg, ExternalConnector conn) { try { final InputStream input = new FileInputStream(ctx.getOutputDirectory() + "/main.js"); final List<String> packLines = IOUtils.readLines(input); String main = ""; for (String line : packLines) { main += line + "\n"; } input.close(); final String url = AnnotatedElementHelper.annotationOrElse(conn.getProtocol(), "server", "127.0.0.1"); final String port = AnnotatedElementHelper.annotationOrElse(conn.getProtocol(), "port", "41234"); main = main.replace("/*$REQUIRE_PLUGINS$*/", "/*$REQUIRE_PLUGINS$*/\nconst UDP = require('./UDPJS');"); main = main.replace("/*$PLUGINS$*/", "/*$PLUGINS$*/\nconst udp = new UDP(\"UDP\", false, " + port + ", \"" + url + "\", " + conn.getInst().getInstance().getName() + ", function (started) {if (!started) {process.exit(1);}});\n"); main = main.replace("/*$STOP_PLUGINS$*/", "udp._stop();\n/*$STOP_PLUGINS$*/\n"); StringBuilder builder = new StringBuilder(); for (Message req : conn.getPort().getSends()) { builder.append(conn.getInst().getInstance().getName() + ".bus.on('" + conn.getPort().getName() + "?" + req.getName() + "', "); builder.append("(msg) => setImmediate(() => udp.receive" + req.getName() + "On" + conn.getPort().getName() + "(msg)"); builder.append("));\n"); /*builder.append(conn.getInst().getInstance().getName() + "." + req.getName() + "On" + conn.getPort().getName() + "Listeners.push("); builder.append("udp.receive" + req.getName() + "On" + conn.getPort().getName() + ".bind(ws)"); builder.append(");\n");*/ } main = main.replace("/*$PLUGINS_CONNECTORS$*/", builder.toString() + "\n/*$PLUGINS_CONNECTORS$*/"); /*if (AnnotatedElementHelper.hasAnnotation(conn.getProtocol(), "server") || AnnotatedElementHelper.hasAnnotation(conn, "server")) { String template = ctx.getTemplateByID("templates/JsWSServer.js"); final String port = AnnotatedElementHelper.annotationOrElse(conn, "server", AnnotatedElementHelper.annotationOrElse(conn.getProtocol(), "server", "9000")); template = template.replace("/*$PORT$*//*", port); main = main.replace("/*$REQUIRE_PLUGINS$*//*", "/*$REQUIRE_PLUGINS$*//*\n" + template); main = main.replace("/*$STOP_PLUGINS$*//*", "wss.close();\n/*$STOP_PLUGINS$*//*\n"); }*/ final File f = new File(ctx.getOutputDirectory() + "/main.js"); final OutputStream output = new FileOutputStream(f); IOUtils.write(main, output, Charset.forName("UTF-8")); IOUtils.closeQuietly(output); } catch (Exception e) { e.printStackTrace(); } } } }