/*
* 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 static java.lang.String.format;
import org.apache.avro.Schema;
import org.kaaproject.kaa.avro.avrogen.compiler.Compiler;
import org.kaaproject.kaa.avro.avrogen.compiler.ObjectiveCCompiler;
import org.kaaproject.kaa.common.dto.event.ApplicationEventAction;
import org.kaaproject.kaa.common.dto.event.ApplicationEventMapDto;
import org.kaaproject.kaa.server.control.service.sdk.CommonSdkUtil;
import org.kaaproject.kaa.server.control.service.sdk.SdkGenerator;
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.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class ObjCEventClassesGenerator {
public static final String KAA_EVENT_PREFIX = "KAAEvent";
private static final Logger LOG = LoggerFactory.getLogger(ObjCEventClassesGenerator.class);
private static final String GEN_ROOT = "Kaa/avro/gen/";
private static final String EVENT_GEN = "EventGen";
private static final String EVENT_FACTORY_PATH = GEN_ROOT + "EventFamilyFactory.";
private static final String EVENT_FAMILY_TEMPLATE = "sdk/objc/event/EventFamily.%s.template";
private static final String EVENT_FAMILY_ADD_SUPPORTED_FQN_TEMPLATE =
"sdk/objc/event/eventFamilyAddSupportedFqn.template";
private static final String EVENT_FAMILY_ON_GENERIC_EVENT_TEMPLATE =
"sdk/objc/event/eventFamilyOnGenericEvent.template";
private static final String EVENT_FAMILY_SEND_EVENT_H_METHODS_TEMPLATE =
"sdk/objc/event/eventFamilySendEventHeaderMethods.template";
private static final String EVENT_FAMILY_SEND_EVENT_M_METHODS_TEMPLATE =
"sdk/objc/event/eventFamilySendEventSourceMethods.template";
private static final String EVENT_FAMILY_LISTENER_METHOD_TEMPLATE =
"sdk/objc/event/eventFamilyListenerMethod.template";
private static final String EVENT_FAMILY_FACTORY_TEMPLATE =
"sdk/objc/event/EventFamilyFactory.%s.template";
private static final String EVENT_FAMILY_FACTORY_METHOD_H_TEMPLATE =
"sdk/objc/event/eventFamilyFactoryMethodHeader.template";
private static final String EVENT_FAMILY_FACTORY_METHOD_M_TEMPLATE =
"sdk/objc/event/eventFamilyFactoryMethodSource.template";
private static final String EVENT_FAMILY_FACTORY_PROPERTY_TEMPLATE =
"sdk/objc/event/eventFamilyFactoryProperty.template";
private static final String EVENT_FAMILY_NAMESPACE_VAR = "\\{event_family_namespace\\}";
private static final String EVENT_FAMILY_CLASS_NAME_VAR = "\\{event_family_class_name\\}";
private static final String EVENT_FAMILY_VAR_NAME_VAR = "\\{event_family_var_name\\}";
private static final String ADD_SUPPORTED_EVENT_CLASS_FQNS_VAR =
"\\{add_supported_event_class_fqns\\}";
private static final String EVENT_FAMILY_LISTENERS_ON_GENERIC_EVENT_VAR =
"\\{event_family_listeners_on_generic_event\\}";
private static final String EVENT_FAMILY_SEND_EVENT_METHODS_VAR =
"\\{event_family_send_event_methods\\}";
private static final String EVENT_FAMILY_LISTENER_METHODS_VAR =
"\\{event_family_listener_methods\\}";
private static final String EVENT_CLASS_FQN_VAR = "\\{event_class_fqn\\}";
private static final String EVENT_CLASS_NAME_VAR = "\\{event_class_name\\}";
private static final String EVENT_FAMILY_FACTORY_IMPORTS_VAR =
"\\{event_family_factory_imports\\}";
private static final String EVENT_FAMILY_FACTORY_PROPERTIES_VAR =
"\\{event_family_factory_properties\\}";
private static final String EVENT_FAMILY_FACTORY_METHODS_VAR =
"\\{event_family_factory_methods\\}";
private static String eventFamilyHeader;
private static String eventFamilySource;
private static String eventFamilyAddSupportedFqn;
private static String eventFamilyOnGenericEvent;
private static String eventFamilySendEventHeaderMethod;
private static String eventFamilySendEventSourceMethod;
private static String eventFamilyListenerMethod;
private static String eventFamilyFactoryHeader;
private static String eventFamilyFactorySource;
private static String eventFamilyFactoryMethodHeader;
private static String eventFamilyFactoryMethodSource;
private static String eventFamilyFactoryProperty;
static {
try {
eventFamilyHeader = SdkGenerator.readResource(format(EVENT_FAMILY_TEMPLATE, "h"));
eventFamilySource = SdkGenerator.readResource(format(EVENT_FAMILY_TEMPLATE, "m"));
eventFamilyAddSupportedFqn = SdkGenerator
.readResource(EVENT_FAMILY_ADD_SUPPORTED_FQN_TEMPLATE);
eventFamilyOnGenericEvent = SdkGenerator.readResource(EVENT_FAMILY_ON_GENERIC_EVENT_TEMPLATE);
eventFamilySendEventHeaderMethod = SdkGenerator
.readResource(EVENT_FAMILY_SEND_EVENT_H_METHODS_TEMPLATE);
eventFamilySendEventSourceMethod = SdkGenerator
.readResource(EVENT_FAMILY_SEND_EVENT_M_METHODS_TEMPLATE);
eventFamilyListenerMethod = SdkGenerator.readResource(EVENT_FAMILY_LISTENER_METHOD_TEMPLATE);
eventFamilyFactoryHeader = SdkGenerator
.readResource(format(EVENT_FAMILY_FACTORY_TEMPLATE, "h"));
eventFamilyFactorySource = SdkGenerator
.readResource(format(EVENT_FAMILY_FACTORY_TEMPLATE, "m"));
eventFamilyFactoryMethodHeader = SdkGenerator
.readResource(EVENT_FAMILY_FACTORY_METHOD_H_TEMPLATE);
eventFamilyFactoryMethodSource = SdkGenerator
.readResource(EVENT_FAMILY_FACTORY_METHOD_M_TEMPLATE);
eventFamilyFactoryProperty = SdkGenerator
.readResource(EVENT_FAMILY_FACTORY_PROPERTY_TEMPLATE);
} catch (IOException ex) {
LOG.error("Unable to initialize ObjCEventClassesGenerator", ex);
}
}
/**
* 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<>();
String eventFamilyFactoryImports = "";
String eventFamilyFactoryProperties = "";
String eventFamilyFactoryMethodsHeader = "";
String eventFamilyFactoryMethodsSource = "";
StringBuilder eventGenHeaderBuilder = new StringBuilder();
StringBuilder eventGenSourceBuilder = new StringBuilder();
LOG.debug("Received {} event families", eventFamilies.size());
HashSet<Schema> generatedSchemas = new HashSet<>();
for (EventFamilyMetadata efm : eventFamilies) {
LOG.debug("Generating schemas for event family {}", efm.getEcfName());
List<Schema> eventCtlSchemas = new ArrayList<>();
efm.getRawCtlsSchemas()
.forEach(rawCtl -> eventCtlSchemas.add(new Schema.Parser().parse(rawCtl)));
try (
OutputStream hdrStream = new ByteArrayOutputStream();
OutputStream srcStream = new ByteArrayOutputStream()
) {
Compiler compiler = new ObjectiveCCompiler(
eventCtlSchemas, EVENT_GEN, hdrStream, srcStream, generatedSchemas);
compiler.setNamespacePrefix(KAA_EVENT_PREFIX);
generatedSchemas.addAll(compiler.generate());
eventGenHeaderBuilder.append(hdrStream.toString()).append("\n");
eventGenSourceBuilder.append(srcStream.toString()).append("\n");
} catch (Exception ex) {
LOG.error("Got exception while generating event classes for event family: "
+ efm.getEcfName(), ex);
}
LOG.error("Processing {}", efm.getEcfName());
eventFamilyFactoryImports += "#import \"" + efm.getEcfClassName() + ".h\"\n";
String eventFamilyVarName = efm.getEcfClassName().substring(0, 1).toLowerCase();
if (efm.getEcfClassName().length() > 1) {
eventFamilyVarName += efm.getEcfClassName().substring(1);
}
eventFamilyFactoryProperties += eventFamilyFactoryProperty
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(EVENT_FAMILY_VAR_NAME_VAR, eventFamilyVarName);
eventFamilyFactoryMethodsHeader += eventFamilyFactoryMethodHeader
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(EVENT_FAMILY_VAR_NAME_VAR, eventFamilyVarName);
eventFamilyFactoryMethodsSource += eventFamilyFactoryMethodSource
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(EVENT_FAMILY_VAR_NAME_VAR, eventFamilyVarName);
String addSupportedEventClassFqns = "";
String eventFamilyListenersOnGenericEvent = "";
String eventFamilySendEventHeaderMethods = "";
String eventFamilySendEventSourceMethods = "";
String eventFamilyListenerMethods = "";
for (ApplicationEventMapDto eventMap : efm.getEventMaps()) {
String eventClassName = eventFqnToClassName(eventMap.getFqn());
if (eventMap.getAction() == ApplicationEventAction.SINK
|| eventMap.getAction() == ApplicationEventAction.BOTH) {
addSupportedEventClassFqns += eventFamilyAddSupportedFqn
.replaceAll(EVENT_CLASS_NAME_VAR, eventClassName)
.replaceAll(EVENT_CLASS_FQN_VAR, eventMap.getFqn());
if (eventFamilyListenersOnGenericEvent.length() > 0) {
eventFamilyListenersOnGenericEvent += "else ";
}
eventFamilyListenersOnGenericEvent += eventFamilyOnGenericEvent
.replaceAll(EVENT_CLASS_NAME_VAR, eventClassName)
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(EVENT_CLASS_FQN_VAR, eventMap.getFqn()) + "\n";
eventFamilyListenerMethods += eventFamilyListenerMethod
.replaceAll(EVENT_CLASS_NAME_VAR, eventClassName)
.replaceAll(EVENT_CLASS_FQN_VAR, eventMap.getFqn()) + "\n";
}
if (eventMap.getAction() == ApplicationEventAction.SOURCE
|| eventMap.getAction() == ApplicationEventAction.BOTH) {
eventFamilySendEventHeaderMethods += eventFamilySendEventHeaderMethod
.replaceAll(EVENT_CLASS_NAME_VAR, eventClassName)
.replaceAll(EVENT_CLASS_FQN_VAR, eventMap.getFqn()) + "\n";
eventFamilySendEventSourceMethods += eventFamilySendEventSourceMethod
.replaceAll(EVENT_CLASS_NAME_VAR, eventClassName)
.replaceAll(EVENT_CLASS_FQN_VAR, eventMap.getFqn()) + "\n";
}
}
String resultFamilyHeader = eventFamilyHeader
.replaceAll(EVENT_FAMILY_NAMESPACE_VAR, efm.getEcfNamespace())
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(ADD_SUPPORTED_EVENT_CLASS_FQNS_VAR, addSupportedEventClassFqns)
.replaceAll(EVENT_FAMILY_LISTENERS_ON_GENERIC_EVENT_VAR,
eventFamilyListenersOnGenericEvent)
.replaceAll(EVENT_FAMILY_SEND_EVENT_METHODS_VAR, eventFamilySendEventHeaderMethods)
.replaceAll(EVENT_FAMILY_LISTENER_METHODS_VAR, eventFamilyListenerMethods);
eventGenHeaderBuilder.append(resultFamilyHeader).append("\n");
String resultFamilySource = eventFamilySource
.replaceAll(EVENT_FAMILY_NAMESPACE_VAR, efm.getEcfNamespace())
.replaceAll(EVENT_FAMILY_CLASS_NAME_VAR, efm.getEcfClassName())
.replaceAll(ADD_SUPPORTED_EVENT_CLASS_FQNS_VAR, addSupportedEventClassFqns)
.replaceAll(EVENT_FAMILY_LISTENERS_ON_GENERIC_EVENT_VAR,
eventFamilyListenersOnGenericEvent)
.replaceAll(EVENT_FAMILY_SEND_EVENT_METHODS_VAR, eventFamilySendEventSourceMethods)
.replaceAll(EVENT_FAMILY_LISTENER_METHODS_VAR, eventFamilyListenerMethods);
eventGenSourceBuilder.append(resultFamilySource).append("\n");
}
eventSources.add(CommonSdkUtil.tarEntryForSources(
eventGenHeaderBuilder.toString(),
GEN_ROOT + EVENT_GEN + ".h"
)
);
eventSources.add(CommonSdkUtil.tarEntryForSources(
eventGenSourceBuilder.toString(),
GEN_ROOT + EVENT_GEN + ".m"
)
);
LOG.debug("Generating event family factory");
String resultEventFamilyFactory = eventFamilyFactoryHeader
.replaceAll(EVENT_FAMILY_FACTORY_IMPORTS_VAR, eventFamilyFactoryImports)
.replaceAll(EVENT_FAMILY_FACTORY_METHODS_VAR, eventFamilyFactoryMethodsHeader);
eventSources.add(CommonSdkUtil.tarEntryForSources(
resultEventFamilyFactory,
EVENT_FACTORY_PATH + "h"
)
);
resultEventFamilyFactory = eventFamilyFactorySource
.replaceAll(EVENT_FAMILY_FACTORY_PROPERTIES_VAR, eventFamilyFactoryProperties)
.replaceAll(EVENT_FAMILY_FACTORY_METHODS_VAR, eventFamilyFactoryMethodsSource);
eventSources.add(CommonSdkUtil.tarEntryForSources(
resultEventFamilyFactory,
EVENT_FACTORY_PATH + "m"
)
);
return eventSources;
}
private static String eventFqnToClassName(String fqn) {
if (fqn == null || fqn.isEmpty()) {
throw new RuntimeException("Failed to get class name from fqn: " + fqn);
}
return KAA_EVENT_PREFIX + fqn.substring(fqn.lastIndexOf('.') + 1);
}
}