/*
* Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.event.receiver.core.internal.type.text;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.databridge.commons.Attribute;
import org.wso2.carbon.databridge.commons.AttributeType;
import org.wso2.carbon.databridge.commons.StreamDefinition;
import org.wso2.carbon.event.receiver.core.InputMapper;
import org.wso2.carbon.event.receiver.core.config.EventReceiverConfiguration;
import org.wso2.carbon.event.receiver.core.config.EventReceiverConstants;
import org.wso2.carbon.event.receiver.core.config.InputMappingAttribute;
import org.wso2.carbon.event.receiver.core.config.mapping.TextInputMapping;
import org.wso2.carbon.event.receiver.core.exception.EventReceiverConfigurationException;
import org.wso2.carbon.event.receiver.core.exception.EventReceiverProcessingException;
import org.wso2.carbon.event.receiver.core.internal.type.text.config.RegexData;
import org.wso2.carbon.event.receiver.core.internal.util.EventReceiverUtil;
import org.wso2.carbon.event.receiver.core.internal.util.helper.EventReceiverConfigurationHelper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.PatternSyntaxException;
public class TextInputMapper implements InputMapper {
private List<RegexData> attributeRegexList = new ArrayList<RegexData>();
private EventReceiverConfiguration eventReceiverConfiguration = null;
private int[] attributePositions;
private static final Log log = LogFactory.getLog(TextInputMapper.class);
private int noMetaData;
private int noCorrelationData;
private int noPayloadData;
private Map<String, AttributeType> attributeDescriptionMap = new LinkedHashMap<>();
private StreamDefinition streamDefinition = null;
public TextInputMapper(EventReceiverConfiguration eventReceiverConfiguration,
StreamDefinition streamDefinition)
throws EventReceiverConfigurationException {
this.eventReceiverConfiguration = eventReceiverConfiguration;
this.streamDefinition = streamDefinition;
if (eventReceiverConfiguration != null && eventReceiverConfiguration.getInputMapping() instanceof TextInputMapping) {
if (eventReceiverConfiguration.getInputMapping().isCustomMappingEnabled()) {
TextInputMapping textInputMapping = (TextInputMapping) eventReceiverConfiguration.getInputMapping();
RegexData regexData = null;
if (textInputMapping.getInputMappingAttributes() != null || textInputMapping.getInputMappingAttributes().size() == 0) {
attributePositions = new int[textInputMapping.getInputMappingAttributes().size()];
} else {
throw new EventReceiverConfigurationException("Text input mapping attribute list cannot be null!");
}
List<Integer> attribPositionList = new LinkedList<Integer>();
for (InputMappingAttribute inputMappingAttribute : textInputMapping.getInputMappingAttributes()) {
String regex = inputMappingAttribute.getFromElementKey();
if (regexData == null || !regex.equals(regexData.getRegex())) {
try {
regexData = new RegexData(regex);
attributeRegexList.add(regexData);
} catch (PatternSyntaxException e) {
throw new EventReceiverConfigurationException("Error parsing regular expression: " + regex, e);
}
}
attribPositionList.add(getEventAttributeLocation(inputMappingAttribute, streamDefinition));
String type = EventReceiverConstants.ATTRIBUTE_TYPE_CLASS_TYPE_MAP.get(inputMappingAttribute.getToElementType());
String defaultValue = inputMappingAttribute.getDefaultValue();
regexData.addMapping(type, defaultValue);
}
for (int i = 0; i < attribPositionList.size(); i++) {
attributePositions[i] = attribPositionList.get(i);
}
} else {
this.noMetaData = streamDefinition.getMetaData() != null ? streamDefinition.getMetaData().size() : 0;
this.noCorrelationData += streamDefinition.getCorrelationData() != null ? streamDefinition.getCorrelationData().size() : 0;
this.noPayloadData += streamDefinition.getPayloadData() != null ? streamDefinition.getPayloadData().size() : 0;
if (noMetaData > 0) {
for (Attribute metaData : streamDefinition.getMetaData()) {
attributeDescriptionMap.put(EventReceiverConstants.META_DATA_PREFIX + metaData.getName(), metaData.getType());
}
}
if (noCorrelationData > 0) {
for (Attribute correlationData : streamDefinition.getCorrelationData()) {
attributeDescriptionMap.put(EventReceiverConstants.CORRELATION_DATA_PREFIX + correlationData.getName(), correlationData.getType());
}
}
if (noPayloadData > 0) {
for (Attribute payloadData : streamDefinition.getPayloadData()) {
attributeDescriptionMap.put(payloadData.getName(), payloadData.getType());
}
}
}
}
}
@Override
public Object convertToMappedInputEvent(Object obj) throws EventReceiverProcessingException {
Object attributeArray[] = new Object[attributePositions.length];
StreamDefinition outStreamDefinition = this.streamDefinition;
int metaDataCount = outStreamDefinition.getMetaData() != null ? outStreamDefinition.getMetaData().size() : 0;
int correlationDataCount = outStreamDefinition.getCorrelationData() != null ? outStreamDefinition.getCorrelationData().size() : 0;
int payloadDataCount = outStreamDefinition.getPayloadData() != null ? outStreamDefinition.getPayloadData().size() : 0;
Object[] metaDataArray = new Object[metaDataCount];
Object[] correlationDataArray = new Object[correlationDataCount];
Object[] payloadDataArray = new Object[payloadDataCount];
if (obj instanceof String) {
String inputString = (String) obj;
int attributeCount = 0;
for (RegexData regexData : attributeRegexList) {
String formattedInputString = inputString.replaceAll("\\r", "");
regexData.matchInput(formattedInputString);
while (regexData.hasNext()) {
Object returnedAttribute = null;
String value = regexData.next();
if (value != null) {
String type = regexData.getType();
try {
Class<?> beanClass = Class.forName(type);
if (!beanClass.equals(String.class)) {
Class<?> stringClass = String.class;
Method valueOfMethod = beanClass.getMethod("valueOf", stringClass);
returnedAttribute = valueOfMethod.invoke(null, value);
} else {
returnedAttribute = value;
}
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new EventReceiverProcessingException("Cannot convert " + value + " to type " + type, e);
} catch (InvocationTargetException e) {
log.warn("Cannot convert " + value + " to type " + type + ": " + e.getMessage() + "; Sending null value.");
}
}
attributeArray[attributePositions[attributeCount++]] = returnedAttribute;
}
}
}
return EventReceiverUtil.getEventFromArray(attributeArray, outStreamDefinition, metaDataArray, correlationDataArray, payloadDataArray);
}
@Override
public Object convertToTypedInputEvent(Object obj) throws EventReceiverProcessingException {
Object attributeArray[] = new Object[noMetaData + noCorrelationData + noPayloadData];
StreamDefinition outStreamDefinition = this.streamDefinition;
int metaDataCount = outStreamDefinition.getMetaData() != null ? outStreamDefinition.getMetaData().size() : 0;
int correlationDataCount = outStreamDefinition.getCorrelationData() != null ? outStreamDefinition.getCorrelationData().size() : 0;
int payloadDataCount = outStreamDefinition.getPayloadData() != null ? outStreamDefinition.getPayloadData().size() : 0;
Object[] metaDataArray = new Object[metaDataCount];
Object[] correlationDataArray = new Object[correlationDataCount];
Object[] payloadDataArray = new Object[payloadDataCount];
if (obj instanceof String) {
String inputString = ((String) obj).trim();
int attributeCount = 0;
String[] eventAttributes = inputString.trim().split(",");
for (String eventAttribute : eventAttributes) {
String[] textEvent = eventAttribute.split(EventReceiverConstants.EVENT_ATTRIBUTE_SEPARATOR);
try {
if (textEvent.length == 2) {
AttributeType attributeType = attributeDescriptionMap.get(textEvent[0].trim());
if (attributeType != null) {
attributeArray[attributeCount++] = getPropertyValue(textEvent[1], attributeType);
} else {
throw new EventReceiverProcessingException("Event attributes are not matching with the stream, hence dropping event attribute " + eventAttribute);
}
} else if (textEvent.length == 0) {
throw new EventReceiverProcessingException("Invalid attribute value found for event ,hence dropping the event " + eventAttribute);
} else if (textEvent.length == 1) {
AttributeType attributeType = attributeDescriptionMap.get(textEvent[0].trim());
if (AttributeType.STRING.equals(attributeType)) {
attributeArray[attributeCount++] = "";
} else {
throw new EventReceiverProcessingException("Attribute value not found in the event, hence dropping event " + eventAttribute);
}
}
} catch (NumberFormatException e) {
throw new EventReceiverProcessingException("Unable to cast the input data to required type for attribute "
+ eventAttribute + ", hence dropping the event.", e);
}
}
if (noMetaData + noCorrelationData + noPayloadData != attributeCount) {
throw new EventReceiverProcessingException("Event attributes are not matching with the stream : " + this.eventReceiverConfiguration.getToStreamName() + ":" + eventReceiverConfiguration.getToStreamVersion());
}
}
return EventReceiverUtil.getEventFromArray(attributeArray, outStreamDefinition, metaDataArray, correlationDataArray, payloadDataArray);
}
@Override
public Attribute[] getOutputAttributes() {
TextInputMapping textInputMapping = (TextInputMapping) eventReceiverConfiguration.getInputMapping();
List<InputMappingAttribute> inputMappingAttributes = textInputMapping.getInputMappingAttributes();
return EventReceiverConfigurationHelper.getAttributes(inputMappingAttributes);
}
private Object getPropertyValue(String propertyValue, AttributeType attributeType) {
if (AttributeType.BOOL.equals(attributeType)) {
return Boolean.parseBoolean(propertyValue);
} else if (AttributeType.DOUBLE.equals(attributeType)) {
return Double.parseDouble(propertyValue);
} else if (AttributeType.FLOAT.equals(attributeType)) {
return Float.parseFloat(propertyValue);
} else if (AttributeType.INT.equals(attributeType)) {
return Integer.parseInt(propertyValue);
} else if (AttributeType.LONG.equals(attributeType)) {
return Long.parseLong(propertyValue);
} else {
return propertyValue;
}
}
private int getEventAttributeLocation(InputMappingAttribute inputMappingAttribute, StreamDefinition streamDefinition) {
int attributeLocation = 0;
int metaSize = streamDefinition.getMetaData() != null ? streamDefinition.getMetaData().size() : 0;
int correlationSize = streamDefinition.getCorrelationData() != null ? streamDefinition.getCorrelationData().size() : 0;
if (EventReceiverUtil.isMetaAttribute(inputMappingAttribute.getToElementKey())) {
for (Attribute metaAttribute : streamDefinition.getMetaData()) {
if ((EventReceiverConstants.META_DATA_PREFIX).concat(metaAttribute.getName()).equals(inputMappingAttribute.getToElementKey())) {
return attributeLocation;
}
attributeLocation++;
}
} else if (EventReceiverUtil.isCorrelationAttribute(inputMappingAttribute.getToElementKey())) {
for (Attribute correlationData : streamDefinition.getCorrelationData()) {
if (EventReceiverConstants.CORRELATION_DATA_PREFIX.concat(correlationData.getName()).equals(inputMappingAttribute.getToElementKey())) {
return attributeLocation + metaSize;
}
attributeLocation++;
}
} else {
for (Attribute payloadData : streamDefinition.getPayloadData()) {
if (payloadData.getName().equals(inputMappingAttribute.getToElementKey())) {
return attributeLocation + metaSize + correlationSize;
}
attributeLocation++;
}
}
return -1;
}
}