/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.wso2.siddhi.extension.input.mapper.map;
import org.apache.log4j.Logger;
import org.wso2.siddhi.annotation.Extension;
import org.wso2.siddhi.core.event.ComplexEventChunk;
import org.wso2.siddhi.core.event.Event;
import org.wso2.siddhi.core.event.stream.MetaStreamEvent;
import org.wso2.siddhi.core.event.stream.StreamEvent;
import org.wso2.siddhi.core.event.stream.StreamEventPool;
import org.wso2.siddhi.core.event.stream.converter.StreamEventConverter;
import org.wso2.siddhi.core.event.stream.converter.ZeroStreamEventConverter;
import org.wso2.siddhi.core.exception.ExecutionPlanRuntimeException;
import org.wso2.siddhi.core.query.output.callback.OutputCallback;
import org.wso2.siddhi.core.stream.input.source.Sourcemapper;
import org.wso2.siddhi.core.stream.input.source.Source;
import org.wso2.siddhi.core.util.AttributeConverter;
import org.wso2.siddhi.core.util.transport.AttributeMapping;
import org.wso2.siddhi.query.api.definition.Attribute;
import org.wso2.siddhi.query.api.definition.StreamDefinition;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This mapper converts hashmap input to {@link ComplexEventChunk}.
*/
@Extension(
name = "map",
namespace = "sourceMapper",
description = ""
)
public class MapSourcemapper implements Sourcemapper {
/**
* Logger to log the events.
*/
private static final Logger log = Logger.getLogger(MapSourcemapper.class);
/**
* SinkCallback to which the converted event must be sent.
*/
private OutputCallback outputCallback;
/**
* Output StreamDefinition of the input mapper.
*/
private StreamDefinition outputStreamDefinition;
/**
* StreamEventPool used to borrow a new event.
*/
private StreamEventPool streamEventPool;
/**
* StreamEventConverter to convert {@link Event} to {@link StreamEvent}.
*/
private StreamEventConverter streamEventConverter;
/**
* Array of information about event mapping.
*/
private MappingPositionData[] mappingPositions;
/**
* Attributes of the output stream.
*/
private List<Attribute> streamAttributes;
/**
* Initialize the mapper and the mapping configurations.
*
* @param outputStreamDefinition the output StreamDefinition
* @param outputCallback the SinkCallback to which the output has to be sent
* @param metaStreamEvent the MetaStreamEvent
* @param options additional mapping options
* @param attributeMappingList list of attributes mapping
*/
@Override
public void init(StreamDefinition outputStreamDefinition, OutputCallback outputCallback, MetaStreamEvent
metaStreamEvent, Map<String, String> options, List<AttributeMapping> attributeMappingList) {
this.outputStreamDefinition = outputStreamDefinition;
this.outputCallback = outputCallback;
this.outputStreamDefinition = metaStreamEvent.getOutputStreamDefinition();
this.streamEventConverter = new ZeroStreamEventConverter();
this.streamEventPool = new StreamEventPool(metaStreamEvent, 5);
this.streamAttributes = this.outputStreamDefinition.getAttributeList();
int attributesSize = this.outputStreamDefinition.getAttributeList().size();
this.mappingPositions = new MappingPositionData[attributesSize];
// Create the position mapping arrays
if (attributeMappingList != null && attributeMappingList.size() > 0) {
// Custom mapping parameters are given
for (int i = 0; i < attributeMappingList.size(); i++) {
// i represents the position of attributes as given by the user in mapping
AttributeMapping attributeMapping = attributeMappingList.get(i);
// The optional name given by the user in attribute mapping
String attributeName = attributeMapping.getRename();
// The position of the attribute in the output stream definition
int position;
if (attributeName != null) {
// Use the name to determine the position
position = outputStreamDefinition.getAttributePosition(attributeName);
} else {
// Use the same order as provided by the user
position = i;
}
this.mappingPositions[i] = new MappingPositionData(position, attributeMapping.getMapping());
}
} else {
// Use the attribute names of the output stream in order
for (int i = 0; i < attributesSize; i++) {
this.mappingPositions[i] = new MappingPositionData(i, this
.outputStreamDefinition.getAttributeList().get(i).getName());
}
}
}
/**
* Receive {@link Event} or Object[] from {@link Source}, convert to {@link ComplexEventChunk} and send
* to the {@link OutputCallback}.
*
* @param eventObject the hashmap
*/
@Override
public void onEvent(Object eventObject) {
StreamEvent borrowedEvent = streamEventPool.borrowEvent();
streamEventConverter.convertEvent(convertToEvent(eventObject), borrowedEvent);
outputCallback.send(new ComplexEventChunk<StreamEvent>(borrowedEvent, borrowedEvent, true));
}
private Event convertToEvent(Object eventObject) {
if (eventObject == null) {
throw new ExecutionPlanRuntimeException("Null object received from the Source to MapsourceMapper");
} else if (!(eventObject instanceof HashMap)) {
throw new ExecutionPlanRuntimeException("Invalid Map object received. Expected HashMap, but found " +
eventObject.getClass()
.getCanonicalName());
}
Event event = new Event(this.outputStreamDefinition.getAttributeList().size());
Object[] data = event.getData();
for (MappingPositionData mappingPositionData : this.mappingPositions) {
int position = mappingPositionData.getPosition();
data[position] = AttributeConverter.getPropertyValue(((HashMap) eventObject).get(mappingPositionData
.getMapping()),
streamAttributes.get(position).getType());
}
return event;
}
/**
* A POJO class which holds the attribute position in output stream and the user defined mapping.
*/
private class MappingPositionData {
/**
* Attribute position in the output stream.
*/
private int position;
/**
* The hashmap mapping as defined by the user.
*/
private String mapping;
public MappingPositionData(int position, String mapping) {
this.position = position;
this.mapping = mapping;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public String getMapping() {
return mapping;
}
public void setMapping(String mapping) {
this.mapping = mapping;
}
}
}