/**
* 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.
*/
/**
*
* @author sintef
*/
package org.thingml.networkplugins.java;
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.java.JavaHelper;
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 JavaJSONSerializerPlugin extends SerializationPlugin {
private Set<Message> messages = new HashSet<Message>();
private void clearMessages() {
messages.clear();
}
private boolean containsMessage(Message m) {
for(Message msg : messages) {
if (EcoreUtil.equals(msg, m)) {
return true;
}
}
return false;
}
private void addMessage(Message m) {
if (!containsMessage(m)) {
messages.add(m);
}
}
private void instantiateMessageType(StringBuilder builder, Message m) {
if (!containsMessage(m)) {
builder.append("private static final " + context.firstToUpper(m.getName()) + "MessageType " + m.getName().toUpperCase() + " = new " + context.firstToUpper(m.getName()) + "MessageType();\n");
addMessage(m);
}
}
@Override
public SerializationPlugin clone() {
return new JavaJSONSerializerPlugin();
}
@Override
public String generateSerialization(StringBuilder builder, String bufferName, Message m, ExternalConnector eco) {
instantiateMessageType(builder, m);
builder.append("/**Serializes a message into a JSON format*/\n");
builder.append("private String format(final " + context.firstToUpper(m.getName()) + "MessageType." + context.firstToUpper(m.getName()) + "Message _this) {\n");
builder.append("final JsonObject msg = new JsonObject();\n");
builder.append("final JsonObject params = new JsonObject();\n");
for (Parameter p : m.getParameters()) {
if(!AnnotatedElementHelper.isDefined(m, "do_not_forward", p.getName())) {
String t = AnnotatedElementHelper.annotationOrElse(p.getType(), "java_type", "void");
if (t.equals("char")) {
builder.append("params.add(\"" + p.getName() + "\", \"\" + _this." + p.getName() + ");\n");
} else {
builder.append("params.add(\"" + p.getName() + "\", _this." + p.getName() + ");\n");
}
}
}
builder.append("msg.add(\"" + m.getName() + "\",params);\n");
builder.append("return msg.toString();\n");
builder.append("}\n\n");
return builder.toString();
}
private void updatePOM(Context ctx) {
//Update POM.xml with JSON Maven dependency
try {
final InputStream input = new FileInputStream(ctx.getOutputDirectory() + "/pom.xml");
final List<String> packLines = IOUtils.readLines(input, Charset.forName("UTF-8"));
String pom = "";
for (String line : packLines) {
pom += line + "\n";
}
input.close();
pom = pom.replace("<!--DEP-->", "<dependency>\n<groupId>com.eclipsesource.minimal-json</groupId>\n<artifactId>minimal-json</artifactId>\n<version>0.9.4</version>\n</dependency>\n<!--DEP-->");
final File f = new File(ctx.getOutputDirectory() + "/pom.xml");
final OutputStream output = new FileOutputStream(f);
IOUtils.write(pom, output, java.nio.charset.Charset.forName("UTF-8"));
IOUtils.closeQuietly(output);
} catch (Exception e) {
e.printStackTrace();
}
}
private void copyInterface() {
final String template = context.getTemplateByID("templates/JavaStringInterface.java");
try {
final File folder = new File(context.getOutputDirectory() + "/src/main/java/org/thingml/generated/network");
folder.mkdir();
final File f = new File(context.getOutputDirectory() + "/src/main/java/org/thingml/generated/network/StringJava.java");
final OutputStream output = new FileOutputStream(f);
IOUtils.write(template, output, Charset.forName("UTF-8"));
IOUtils.closeQuietly(output);
} catch (Exception e) {
e.printStackTrace();
}
final String template2 = context.getTemplateByID("templates/JavaFormat.java");
try {
final File folder = new File(context.getOutputDirectory() + "/src/main/java/org/thingml/generated/network");
folder.mkdir();
final File f = new File(context.getOutputDirectory() + "/src/main/java/org/thingml/generated/network/Format.java");
final OutputStream output = new FileOutputStream(f);
IOUtils.write(template2, output, Charset.forName("UTF-8"));
IOUtils.closeQuietly(output);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void generateParserBody(StringBuilder builder, String bufferName, String bufferSizeName, Set<Message> messages, String sender, ExternalConnector eco) {
updatePOM(context);
copyInterface();
builder.append("package org.thingml.generated.network;\n\n");
builder.append("import org.thingml.generated.messages.*;\n");
builder.append("import org.thingml.java.ext.Event;\n");
builder.append("import com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonValue;\nimport com.eclipsesource.json.Json;\n");
builder.append("public class " + bufferName + " implements StringJava {\n");
for(Message m : messages) {
instantiateMessageType(builder, m);
}
//Instantiate message from binary
builder.append("public Event instantiate(String payload) {\n");
builder.append("try{\n");
builder.append("final JsonObject msg = Json.parse(payload).asObject();\n");
builder.append("final String msgName = msg.names().get(0);\n");
boolean isFirst = true;
for(Message m : messages) {
if(isFirst) {
isFirst = false;
} else {
builder.append("else ");
}
builder.append("if(msgName.equals(" + m.getName().toUpperCase() + ".getName())){\n");
builder.append("return " + m.getName().toUpperCase() + ".instantiate(");
for (Parameter p : m.getParameters()) {
if(!AnnotatedElementHelper.isDefined(m, "do_not_forward", p.getName())) {
if (m.getParameters().indexOf(p) > 0)
builder.append(", ");
builder.append("(" + JavaHelper.getJavaType(p.getType(), p.getCardinality() != null, context) + ") ");
builder.append("msg.get(msgName).asObject().get(\"" + p.getName() + "\")");
String getter = "asString()";
switch (AnnotatedElementHelper.annotationOrElse(p.getType(), "java_type", "void")) {
case "short": getter = "asInt()"; break;
case "int": getter = "asInt()"; break;
case "long": getter = "asInt()"; break;
case "float": getter = "asFloat()"; break;
case "double": getter = "asDouble()"; break;
case "byte": getter = "asInt()"; break;
case "boolean": getter = "asBoolean()"; break;
case "char": getter = "asString().charAt(0)"; break;
default: break;
}
builder.append("." + getter);
}
}
builder.append(");\n}\n");
}
builder.append("\n}catch(Exception pe){\n");
builder.append("System.out.println(\"Cannot parse \" + payload + \" because of \" + pe.getMessage());\n");
builder.append("}\n");
builder.append("return null;\n");
builder.append("}\n");
builder.append("/*$SERIALIZERS$*/\n\n");
builder.append("}\n");
}
@Override
public String getPluginID() {
return "JavaJSONSerializerPlugin";
}
@Override
public List<String> getTargetedLanguages() {
List<String> res = new ArrayList<>();
res.add("java");
return res;
}
@Override
public List<String> getSupportedFormat() {
List<String> res = new ArrayList<>();
res.add("JSON");
return res;
}
}