/*
* Copyright 2014-2016 CyberVision, Inc.
*
* 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.
*/
package org.kaaproject.kaa.server.control.service.sdk.event;
import org.apache.avro.Schema;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.kaaproject.kaa.avro.avrogen.StyleUtils;
import org.kaaproject.kaa.avro.avrogen.compiler.CCompiler;
import org.kaaproject.kaa.avro.avrogen.compiler.Compiler;
import org.kaaproject.kaa.common.dto.event.ApplicationEventAction;
import org.kaaproject.kaa.common.dto.event.ApplicationEventMapDto;
import org.kaaproject.kaa.server.control.service.sdk.compress.TarEntryData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
public class CEventSourcesGenerator {
/**
* The Constant logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(CppEventSourcesGenerator.class);
/**
* The KAA_SRC_FOLDER variable is also set in CMakeList.txt located in the root folder of the C
* SDK project.
*/
private static final String KAA_SRC_FOLDER = "src/kaa";
private static final String EVENT_SOURCE_OUTPUT = KAA_SRC_FOLDER + "/gen/";
private static final String NAME_PREFIX_TEMPLATE = "kaa_{name}";
private static final String EVENT_FAMILY_DEFINITION_PATTERN = "kaa_{name}_definitions";
private static final String EVENT_FAMILIES_H_PATTERN = "sdk/c/event/kaa_event_families.hvm";
private static final String EVENT_FAMILIES_H_FILE = "kaa_{name}.h";
private static final String EVENT_FAMILIES_C_PATTERN = "sdk/c/event/kaa_event_families.cvm";
private static final String EVENT_FAMILIES_C_FILE = "kaa_{name}.c";
private static final String EVENT_FQN_H_FILE = "kaa_event_fqn_definitions.h";
private static final String EVENT_FQN_PATTERN = "sdk/c/event/kaa_event_fqn_definitions.hvm";
private static final VelocityEngine velocityEngine; //NOSONAR
static {
velocityEngine = new VelocityEngine();
velocityEngine.addProperty("resource.loader", "class, file");
velocityEngine.addProperty("class.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
velocityEngine.addProperty("file.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.FileResourceLoader");
velocityEngine.addProperty("file.resource.loader.path", "/, .");
velocityEngine.setProperty("runtime.references.strict", true);
velocityEngine.setProperty("runtime.log.logsystem.class",
"org.apache.velocity.runtime.log.NullLogSystem");
}
/**
* Create new zip entry data for the event family metadata.
*
* @param eventFamilies the event family metadata
* @return a new zip entry data
*/
public static List<TarEntryData> generateEventSources(List<EventFamilyMetadata> eventFamilies) {
List<TarEntryData> eventSources = new ArrayList<>();
LOG.debug("[sdk generateEventSources] eventFamilies.size(): {}", eventFamilies.size());
VelocityContext context = new VelocityContext();
context.put("eventFamilies", eventFamilies);
StringWriter commonWriter = new StringWriter();
velocityEngine.getTemplate(EVENT_FQN_PATTERN).merge(context, commonWriter);
for (EventFamilyMetadata eventFamily : eventFamilies) {
context.put("StyleUtils", StyleUtils.class);
String name = StyleUtils.toLowerUnderScore(eventFamily.getEcfClassName());
String nameUpperCase = StyleUtils.toUpperUnderScore(eventFamily.getEcfClassName());
context.put("event_family_name", name);
context.put("EVENT_FAMILY_NAME", nameUpperCase);
context.put("namespacePrefix", NAME_PREFIX_TEMPLATE.replace("{name}", name));
List<Schema> records = new ArrayList<>();
eventFamily.getRawCtlsSchemas()
.forEach(rawCtl -> records.add(new Schema.Parser().parse(rawCtl)));
List<String> emptyRecords = new ArrayList<>();
for (Schema record : records) {
if (record.getType() == Schema.Type.RECORD
&& record.getFields() != null && record.getFields().size() == 0) {
emptyRecords.add(record.getFullName());
}
}
context.put("emptyRecords", emptyRecords);
List<String> incomingEventFqns = new ArrayList<>();
List<String> outgoingEventFqns = new ArrayList<>();
if (eventFamily.getEventMaps() != null) {
for (ApplicationEventMapDto appEventDto : eventFamily.getEventMaps()) {
if (appEventDto.getAction() == ApplicationEventAction.SINK
|| appEventDto.getAction() == ApplicationEventAction.BOTH) {
incomingEventFqns.add(appEventDto.getFqn());
}
if (appEventDto.getAction() == ApplicationEventAction.SOURCE
|| appEventDto.getAction() == ApplicationEventAction.BOTH) {
outgoingEventFqns.add(appEventDto.getFqn());
}
}
}
context.put("incomingEventFqns", incomingEventFqns);
context.put("outgoingEventFqns", outgoingEventFqns);
StringWriter headerWriter = new StringWriter();
LOG.debug("[sdk generateEventSources] header generating:");
velocityEngine.getTemplate(EVENT_FAMILIES_H_PATTERN).merge(context, headerWriter);
TarArchiveEntry entry = new TarArchiveEntry(EVENT_SOURCE_OUTPUT
+ EVENT_FAMILIES_H_FILE.replace("{name}", name));
LOG.debug("[sdk generateEventSources] header generated: {}", entry.getName());
byte[] data = headerWriter.toString().getBytes();
entry.setSize(data.length);
TarEntryData tarEntry = new TarEntryData(entry, data);
eventSources.add(tarEntry);
StringWriter sourceWriter = new StringWriter();
LOG.debug("[sdk generateEventSources] source generating:");
velocityEngine.getTemplate(EVENT_FAMILIES_C_PATTERN).merge(context, sourceWriter);
entry = new TarArchiveEntry(EVENT_SOURCE_OUTPUT
+ EVENT_FAMILIES_C_FILE.replace("{name}", name));
LOG.debug("[sdk generateEventSources] source generated: {}", entry.getName());
data = sourceWriter.toString().getBytes();
entry.setSize(data.length);
tarEntry = new TarEntryData(entry, data);
eventSources.add(tarEntry);
entry = new TarArchiveEntry(EVENT_SOURCE_OUTPUT + EVENT_FQN_H_FILE);
data = commonWriter.toString().getBytes();
entry.setSize(data.length);
tarEntry = new TarEntryData(entry, data);
eventSources.add(tarEntry);
try (
OutputStream hdrStream = new ByteArrayOutputStream();
OutputStream srcStream = new ByteArrayOutputStream()
) {
String fileName = EVENT_FAMILY_DEFINITION_PATTERN.replace("{name}", name);
List<Schema> eventCtlSchemas = new ArrayList<>();
eventFamily.getRawCtlsSchemas()
.forEach(rawCtl -> eventCtlSchemas.add(new Schema.Parser().parse(rawCtl)));
Compiler compiler = new CCompiler(eventCtlSchemas, fileName, hdrStream, srcStream);
compiler.setNamespacePrefix(NAME_PREFIX_TEMPLATE.replace("{name}", name));
compiler.generate();
String eventData = hdrStream.toString();
entry = new TarArchiveEntry(EVENT_SOURCE_OUTPUT + fileName + ".h");
entry.setSize(eventData.length());
tarEntry = new TarEntryData(entry, eventData.getBytes());
eventSources.add(tarEntry);
entry = new TarArchiveEntry(EVENT_SOURCE_OUTPUT + fileName + ".c");
eventData = srcStream.toString();
entry.setSize(eventData.length());
tarEntry = new TarEntryData(entry, eventData.getBytes());
eventSources.add(tarEntry);
} catch (Exception ex) {
LOG.error("got exception", ex);
}
}
LOG.debug("[sdk generateEventSources] exit. Generated {} files", eventSources.size());
return eventSources;
}
}