/*
* Copyright 2016 ANI Technologies Pvt. Ltd.
*
* 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 com.olacabs.fabric.compute.builder;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.olacabs.fabric.compute.ProcessingContext;
import com.olacabs.fabric.compute.pipeline.ComputationPipeline;
import com.olacabs.fabric.compute.pipeline.NotificationBus;
import com.olacabs.fabric.compute.pipeline.PipelineStage;
import com.olacabs.fabric.compute.processor.ProcessorBase;
import com.olacabs.fabric.compute.source.PipelineSource;
import com.olacabs.fabric.compute.source.PipelineStreamSource;
import com.olacabs.fabric.model.common.ComponentMetadata;
import com.olacabs.fabric.model.computation.ComputationSpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* TODO javadoc.
*/
public class Linker {
private static final Logger LOGGER = LoggerFactory.getLogger(Linker.class);
private static final String DEFAULT_REGISTRY_NAME = "metrics-registry";
private final Loader loader;
private MetricRegistry metricRegistry;
public Linker(Loader loader) {
this(loader, SharedMetricRegistries.getOrCreate(DEFAULT_REGISTRY_NAME));
}
public Linker(Loader loader, MetricRegistry metricRegistry) {
this.loader = loader;
this.metricRegistry = metricRegistry;
}
public ComputationPipeline build(ComputationSpec spec) {
final NotificationBus notificationBus = new NotificationBus(spec.getProperties());
final ProcessingContext processingContext = new ProcessingContext();
processingContext.setTopologyName(spec.getName());
ComputationPipeline pipeline = ComputationPipeline.builder();
pipeline.notificationBus(notificationBus);
pipeline.computationName(spec.getName());
Map<String, PipelineStreamSource> sources = Maps.newHashMap();
Map<String, PipelineStage> stages = Maps.newHashMap();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
spec.getSources().forEach(sourceMetadata -> {
final ComponentMetadata meta = sourceMetadata.getMeta();
PipelineSource source = null;
final String errorMessage = String.format("Source object not loaded properly [%s:%s:%s]",
meta.getNamespace(), meta.getName(), meta.getVersion());
try {
PipelineSource sourceCopy = loader.loadSource(meta);
if (sourceCopy != null) {
source = sourceCopy.getClass().getDeclaredConstructor().newInstance();
}
} catch (Exception e) {
throw new RuntimeException(errorMessage, e);
}
Preconditions.checkNotNull(source, errorMessage);
LOGGER.info("Loaded source: {}:{}:{}",
meta.getNamespace(), meta.getName(), meta.getVersion());
PipelineStreamSource sourceStage = PipelineStreamSource.builder()
.instanceId(sourceMetadata.getId())
.properties(sourceMetadata.getProperties())
.notificationBus(notificationBus)
.sourceMetadata(sourceMetadata.getMeta())
.source(source)
.processingContext(processingContext)
.objectMapper(objectMapper)
.registry(metricRegistry)
.build();
pipeline.addSource(sourceStage);
sources.put(sourceMetadata.getId(), sourceStage);
});
spec.getProcessors().forEach(processorMetadata -> {
final ComponentMetadata meta = processorMetadata.getMeta();
ProcessorBase processorBase = null;
final String errorMessage = String.format("Processor object not loaded properly [%s:%s:%s]",
meta.getNamespace(), meta.getName(), meta.getVersion());
try {
ProcessorBase processorBaseCopy = loader.loadProcessor(meta);
if (processorBaseCopy != null) {
processorBase = processorBaseCopy.getClass().getDeclaredConstructor().newInstance();
}
} catch (Exception e) {
throw new RuntimeException(errorMessage, e);
}
Preconditions.checkNotNull(processorBase, errorMessage);
LOGGER.info("Loaded processor: {}:{}:{}",
meta.getNamespace(), meta.getName(), meta.getVersion());
PipelineStage stage = PipelineStage.builder()
.instanceId(processorMetadata.getId())
.properties(processorMetadata.getProperties())
.notificationBus(notificationBus)
.processorMetadata(processorMetadata.getMeta())
.processor(processorBase)
.context(processingContext)
.build();
pipeline.addPipelineStage(stage);
stages.put(processorMetadata.getId(), stage);
});
spec.getConnections().forEach(connection -> {
switch (connection.getFromType()) {
case SOURCE:
pipeline.connect(sources.get(connection.getFrom()), stages.get(connection.getTo()));
break;
case PROCESSOR:
pipeline.connect(stages.get(connection.getFrom()), stages.get(connection.getTo()));
break;
default: break;
}
});
return pipeline;
}
}