/**
* 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.
*/
package org.thingml.networkplugins.c.posix;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.sintef.thingml.ExternalConnector;
import org.sintef.thingml.Message;
import org.sintef.thingml.Parameter;
import org.sintef.thingml.PlatformAnnotation;
import org.sintef.thingml.helpers.AnnotatedElementHelper;
import org.sintef.thingml.impl.ParameterImpl;
import org.thingml.compilers.c.CCompilerContext;
import org.thingml.compilers.spi.SerializationPlugin;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by jakobho on 01.02.2017.
*/
public class PosixTelluCloudSerializerPlugin extends PosixJSONSerializerPlugin {
@Override
public SerializationPlugin clone() {
return new PosixTelluCloudSerializerPlugin();
}
@Override
public String getPluginID() {
return "PosixTelluCloudSerializerPlugin";
}
@Override
String getJSONParameterName(Message m, Parameter p, CCompilerContext ctx) {
String original = super.getJSONParameterName(m, p, ctx);
// Replace any underscore with a dot
return original.replace('_','.');
}
@Override
Integer getMaximumSerializedParameterValueLength(Parameter p, CCompilerContext ctx, ExternalConnector eco) {
if (p.getName().equals("deviceId")) {
// This will be a string literal given by an annotation
String deviceId = AnnotatedElementHelper.annotationOrElse(eco, "tellucloud_deviceid", "");
if (deviceId.isEmpty()) deviceId = AnnotatedElementHelper.annotationOrElse(eco.getProtocol(), "tellucloud_deviceid", "");
if (deviceId.isEmpty()) return 4; // Print a null
else return deviceId.length()+2; // String + surrounding '""'
} else if (p.getName().equals("observations")) {
TelluCloudGroupedParameter grouped = (TelluCloudGroupedParameter)p;
// Return the length of the set and the contained grouped parameters
Integer length = 2; // '[]' Base group array JSON
for (Parameter gp : grouped.m.getParameters()) {
length += getMaximumSerializedParameterLength(gp, ctx, eco);
length += 2; // Surrounding '{}'
}
return length;
} else {
return super.getMaximumSerializedParameterValueLength(p, ctx, eco);
}
}
@Override
void generateParameterValueSerialization(StringBuilder builder, String bufferName, Integer maxLength, Parameter p, CCompilerContext ctx, ExternalConnector eco) {
if (p.getName().equals("deviceId")) {
// Print the string literal given by the annotation
String deviceId = AnnotatedElementHelper.annotationOrElse(eco, "tellucloud_deviceid", "");
if (deviceId.isEmpty()) deviceId = AnnotatedElementHelper.annotationOrElse(eco.getProtocol(), "tellucloud_deviceid", "");
if (deviceId.isEmpty()) deviceId = "null";
else deviceId = "\\\""+deviceId+"\\\"";
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \""+deviceId+"\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
} else if (p.getName().equals("observations")) {
TelluCloudGroupedParameter grouped = (TelluCloudGroupedParameter)p;
// This is our special grouped placeholder
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \"[\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
builder.append(" /* ---------- Start Tellu Cloud grouped observations ---------- */\n");
// Generate the normal JSON parameters to put inside the group
StringBuilder original = new StringBuilder();
generateParameterSerializations(original, bufferName, maxLength, grouped.m, ctx, eco);
// Modify to wrap each parameter inside an object '{}'
Boolean first = true;
Pattern regex = Pattern.compile("^\\s*result = sprintf[^,]+,\\s*\"%\\.\\*s\"[^\"]+(\",\\\\\")[^\"]+\":\"\\);$");
for (String line : original.toString().split("\\n")) {
if (line.matches("\\s*// Parameter.+")) {
// Start of parameter, given by the '...// Parameter ...' string on the line
// Start object
if (!first){
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \"}\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
}
// Normal comment line
builder.append(line+"\n");
// End object
String separator = "";
if (!first) separator = ",";
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \""+separator+"{\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
first = false;
} else {
// Replace comma separators before parameter names
Matcher m = regex.matcher(line);
if (m.matches()) {
line = line.substring(0,m.start(1)) + "\"\\\"" + line.substring(m.end(1));
}
builder.append(line+"\n");
}
}
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \"}\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
// End of special grouped placeholder
builder.append(" /* ----------- End Tellu Cloud grouped observations ----------- */\n");
builder.append(" result = sprintf(&"+bufferName+"[index], \"%.*s\", "+maxLength+"-index, \"]\");\n");
builder.append(" if (result >= 0) { index += result; } else { return; }\n");
} else {
// Any other parameter is serialized normally
super.generateParameterValueSerialization(builder, bufferName, maxLength, p, ctx, eco);
}
}
@Override
public String generateSerialization(StringBuilder builder, String bufferName, Message m, ExternalConnector eco) {
if (AnnotatedElementHelper.isDefined(m, "tellucloud_type", "observation")) {
Message msg = EcoreUtil.copy(m);
// Add the deviceID parameter
Parameter deviceID = EcoreUtil.copy(msg.getParameters().get(0));
deviceID.setName("deviceId");
msg.getParameters().add(0,deviceID);
// Remove the grouped parameters from the modified message
List<Parameter> grouped = msg.getParameters().subList(2,msg.getParameters().size());
List<Parameter> groupedCopy = new ArrayList<>(grouped);
grouped.clear();
// Add the custom-handling grouped parameter
Message placeholderMsg = EcoreUtil.copy(m);
placeholderMsg.getParameters().clear();
placeholderMsg.getParameters().addAll(groupedCopy);
Parameter placeholder = new TelluCloudGroupedParameter(placeholderMsg);
grouped.add(placeholder);
// Set the @json_message_name annotation
PlatformAnnotation jsonMsgName = EcoreUtil.copy(msg.getAnnotations().get(0));
jsonMsgName.setName("json_message_name");
jsonMsgName.setValue("observation");
msg.getAnnotations().add(jsonMsgName);
// Generate JSON serialisation of modified message
return super.generateSerialization(builder, bufferName, msg, eco);
} else {
// Generate normal JSON serialisation
return super.generateSerialization(builder, bufferName, m, eco);
}
}
@Override
public void generateParserBody(StringBuilder builder, String bufferName, String bufferSizeName, Set<Message> messages, String sender, ExternalConnector eco) {
super.generateParserBody(builder, bufferName, bufferSizeName, messages, sender, eco);
}
/* CUSTOM PARAMETER TO HOLD GROUPING */
private class TelluCloudGroupedParameter extends ParameterImpl {
Message m;
public TelluCloudGroupedParameter(Message msg)
{
super();
this.setName("observations");
this.m = msg;
}
}
}