/* * Copyright (c) 2015, 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.carbon.event.receiver.core.internal.type.wso2event; import org.wso2.carbon.databridge.commons.Attribute; import org.wso2.carbon.databridge.commons.Event; 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.InputMapping; import org.wso2.carbon.event.receiver.core.config.InputMappingAttribute; import org.wso2.carbon.event.receiver.core.config.mapping.WSO2EventInputMapping; 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.exception.EventReceiverStreamValidationException; import org.wso2.carbon.event.receiver.core.internal.ds.EventReceiverServiceValueHolder; import org.wso2.carbon.event.receiver.core.internal.util.EventReceiverUtil; import org.wso2.carbon.event.receiver.core.internal.util.helper.EventReceiverConfigurationHelper; import org.wso2.carbon.event.stream.core.EventStreamService; import org.wso2.carbon.event.stream.core.exception.EventStreamConfigurationException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; public class WSO2EventInputMapper implements InputMapper { private EventReceiverConfiguration eventReceiverConfiguration = null; private StreamDefinition exportedStreamDefinition = null; private StreamDefinition importedStreamDefinition = null; private Map<InputDataType, int[]> inputDataTypeSpecificPositionMap = null; private boolean arbitraryMapsEnabled = false; private int inputStreamSize = 0; private int outMetaSize = 0, outCorrelationSize = 0, outPayloadSize = 0; public WSO2EventInputMapper(EventReceiverConfiguration eventReceiverConfiguration, StreamDefinition exportedStreamDefinition) throws EventReceiverConfigurationException { //TODO It is better if logic to check from stream definition store can be moved outside of input mapper. EventStreamService eventStreamService = EventReceiverServiceValueHolder.getEventStreamService(); this.eventReceiverConfiguration = eventReceiverConfiguration; WSO2EventInputMapping wso2EventInputMapping = (WSO2EventInputMapping) this.eventReceiverConfiguration.getInputMapping(); String fromStreamName = wso2EventInputMapping.getFromEventName(); String fromStreamVersion = wso2EventInputMapping.getFromEventVersion(); this.arbitraryMapsEnabled = wso2EventInputMapping.isArbitraryMapsEnabled(); if (fromStreamName == null || fromStreamVersion == null || (fromStreamName.isEmpty()) || (fromStreamVersion.isEmpty())) { importedStreamDefinition = exportedStreamDefinition; } else { try { this.importedStreamDefinition = eventStreamService.getStreamDefinition(fromStreamName, fromStreamVersion); } catch (EventStreamConfigurationException e) { throw new EventReceiverStreamValidationException("Error while retrieving stream definition : " + e.getMessage(), fromStreamName + ":" + fromStreamVersion); } } this.exportedStreamDefinition = exportedStreamDefinition; if (importedStreamDefinition == null) { // Import stream for custom mapping is not available String fromStream = fromStreamName + EventReceiverConstants.STREAM_NAME_VER_DELIMITER + fromStreamVersion; throw new EventReceiverStreamValidationException("Imported stream " + fromStream + " is not available", fromStream); } boolean candidateForArbitraryMaps = isCandidateForArbitraryAttributes(eventReceiverConfiguration.getInputMapping(), importedStreamDefinition); if (!candidateForArbitraryMaps) { validateInputStreamAttributes(); } if (importedStreamDefinition != null && eventReceiverConfiguration.getInputMapping().isCustomMappingEnabled() && !candidateForArbitraryMaps) { this.inputDataTypeSpecificPositionMap = new HashMap<InputDataType, int[]>(); Map<Integer, Integer> payloadDataMap = new TreeMap<Integer, Integer>(); Map<Integer, Integer> metaDataMap = new TreeMap<Integer, Integer>(); Map<Integer, Integer> correlationDataMap = new TreeMap<Integer, Integer>(); List<Attribute> allAttributes = new ArrayList<Attribute>(); if (importedStreamDefinition.getMetaData() != null && !importedStreamDefinition.getMetaData().isEmpty()) { allAttributes.addAll(importedStreamDefinition.getMetaData()); } if (importedStreamDefinition.getCorrelationData() != null && !importedStreamDefinition.getCorrelationData().isEmpty()) { allAttributes.addAll(importedStreamDefinition.getCorrelationData()); } if (importedStreamDefinition.getPayloadData() != null && !importedStreamDefinition.getPayloadData().isEmpty()) { allAttributes.addAll(importedStreamDefinition.getPayloadData()); } int metaCount = 0, correlationCount = 0, payloadCount = 0; for (InputMappingAttribute inputMappingAttribute : wso2EventInputMapping.getInputMappingAttributes()) { if (inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.META_DATA_PREFIX)) { for (int i = 0; i < allAttributes.size(); i++) { if (allAttributes.get(i).getName().equals(inputMappingAttribute.getFromElementKey())) { metaDataMap.put(metaCount, i); break; } } if (metaDataMap.get(metaCount++) == null) { this.inputDataTypeSpecificPositionMap = null; throw new EventReceiverStreamValidationException("Cannot find a corresponding meta data input attribute '" + inputMappingAttribute.getFromElementKey() + "' in stream with id " + importedStreamDefinition.getStreamId(), importedStreamDefinition.getStreamId()); } } else if (inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.CORRELATION_DATA_PREFIX)) { for (int i = 0; i < allAttributes.size(); i++) { if (allAttributes.get(i).getName().equals(inputMappingAttribute.getFromElementKey())) { correlationDataMap.put(correlationCount, i); break; } } if (correlationDataMap.get(correlationCount++) == null) { this.inputDataTypeSpecificPositionMap = null; throw new EventReceiverStreamValidationException("Cannot find a corresponding correlation data input attribute '" + inputMappingAttribute.getFromElementKey() + "' in stream with id " + importedStreamDefinition.getStreamId(), importedStreamDefinition.getStreamId()); } } else { for (int i = 0; i < allAttributes.size(); i++) { if (allAttributes.get(i).getName().equals(inputMappingAttribute.getFromElementKey())) { payloadDataMap.put(payloadCount, i); break; } } if (payloadDataMap.get(payloadCount++) == null) { this.inputDataTypeSpecificPositionMap = null; throw new EventReceiverStreamValidationException("Cannot find a corresponding payload data input attribute '" + inputMappingAttribute.getFromElementKey() + "' in stream with id : " + importedStreamDefinition.getStreamId(), importedStreamDefinition.getStreamId()); } } } outMetaSize = metaDataMap.size(); outCorrelationSize = correlationDataMap.size(); outPayloadSize = payloadDataMap.size(); int[] metaPositions = new int[outMetaSize]; for (int i = 0; i < metaPositions.length; i++) { metaPositions[i] = metaDataMap.get(i); } inputDataTypeSpecificPositionMap.put(InputDataType.META_DATA, metaPositions); int[] correlationPositions = new int[outCorrelationSize]; for (int i = 0; i < correlationPositions.length; i++) { correlationPositions[i] = correlationDataMap.get(i); } inputDataTypeSpecificPositionMap.put(InputDataType.CORRELATION_DATA, correlationPositions); int[] payloadPositions = new int[outPayloadSize]; for (int i = 0; i < payloadPositions.length; i++) { payloadPositions[i] = payloadDataMap.get(i); } inputDataTypeSpecificPositionMap.put(InputDataType.PAYLOAD_DATA, payloadPositions); inputStreamSize = allAttributes.size(); } else if (importedStreamDefinition != null && (!eventReceiverConfiguration.getInputMapping().isCustomMappingEnabled())) { if (importedStreamDefinition.getCorrelationData() != null ? !importedStreamDefinition.getCorrelationData().equals(exportedStreamDefinition.getCorrelationData()) : exportedStreamDefinition.getCorrelationData() != null) { throw new EventReceiverStreamValidationException("Input stream definition : " + importedStreamDefinition + " not matching with output stream definition : " + exportedStreamDefinition + " to create pass-through link ", importedStreamDefinition.getStreamId()); } if (importedStreamDefinition.getMetaData() != null ? !importedStreamDefinition.getMetaData().equals(exportedStreamDefinition.getMetaData()) : exportedStreamDefinition.getMetaData() != null) { throw new EventReceiverStreamValidationException("Input stream definition : " + importedStreamDefinition + " not matching with output stream definition : " + exportedStreamDefinition + " to create pass-through link ", importedStreamDefinition.getStreamId()); } if (importedStreamDefinition.getPayloadData() != null ? !importedStreamDefinition.getPayloadData().equals(exportedStreamDefinition.getPayloadData()) : exportedStreamDefinition.getPayloadData() != null) { throw new EventReceiverStreamValidationException("Input stream definition : " + importedStreamDefinition + " not matching with output stream definition : " + exportedStreamDefinition + " to create pass-through link ", importedStreamDefinition.getStreamId()); } } else if (!candidateForArbitraryMaps) { throw new EventReceiverStreamValidationException("Error while retrieving stream definition : " + fromStreamName + ":" + fromStreamVersion); } } private boolean isCandidateForArbitraryAttributes(InputMapping inputMapping, StreamDefinition importedStreamDefinition) { for (InputMappingAttribute inputMappingAttribute : inputMapping.getInputMappingAttributes()) { if (EventReceiverConstants.META_DATA_VAL.equals(inputMappingAttribute.getFromElementType()) && !importedStreamDefinition.getMetaData().contains(new Attribute(inputMappingAttribute.getFromElementKey(), inputMappingAttribute.getToElementType()))) { return true; } if (EventReceiverConstants.CORRELATION_DATA_VAL.equals(inputMappingAttribute.getFromElementType()) && !importedStreamDefinition.getCorrelationData().contains(new Attribute(inputMappingAttribute.getFromElementKey(), inputMappingAttribute.getToElementType()))) { return true; } if (EventReceiverConstants.PAYLOAD_DATA_VAL.equals(inputMappingAttribute.getFromElementType()) && !importedStreamDefinition.getPayloadData().contains(new Attribute(inputMappingAttribute.getFromElementKey(), inputMappingAttribute.getToElementType()))) { return true; } } return false; } private void validateInputStreamAttributes() throws EventReceiverConfigurationException { if (this.importedStreamDefinition != null) { WSO2EventInputMapping wso2EventInputMapping = (WSO2EventInputMapping) eventReceiverConfiguration.getInputMapping(); List<InputMappingAttribute> inputMappingAttributes = wso2EventInputMapping.getInputMappingAttributes(); List<String> inputStreamMetaAttributeNames = getAttributeNamesList(importedStreamDefinition.getMetaData()); List<String> inputStreamCorrelationAttributeNames = getAttributeNamesList(importedStreamDefinition.getCorrelationData()); List<String> inputStreamPayloadAttributeNames = getAttributeNamesList(importedStreamDefinition.getPayloadData()); for (InputMappingAttribute inputMappingAttribute : inputMappingAttributes) { if (inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.META_DATA_PREFIX) && !inputStreamMetaAttributeNames.contains(inputMappingAttribute.getFromElementKey())) { throw new EventReceiverStreamValidationException("Property " + inputMappingAttribute.getFromElementKey() + " is not in the input stream definition. ", importedStreamDefinition.getStreamId()); } else if (inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.CORRELATION_DATA_PREFIX) && !inputStreamCorrelationAttributeNames.contains(inputMappingAttribute.getFromElementKey())) { throw new EventReceiverStreamValidationException("Property " + inputMappingAttribute.getFromElementKey() + " is not in the input stream definition. ", importedStreamDefinition.getStreamId()); } else if (!inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.META_DATA_PREFIX) && !inputMappingAttribute.getToElementKey().startsWith(EventReceiverConstants.CORRELATION_DATA_PREFIX) && !inputStreamPayloadAttributeNames.contains(inputMappingAttribute.getFromElementKey())) { throw new EventReceiverStreamValidationException("Property " + inputMappingAttribute.getFromElementKey() + " is not in the input stream definition. ", importedStreamDefinition.getStreamId()); } } } } private List<String> getAttributeNamesList(List<Attribute> attributeList) { List<String> attributeNamesList = new ArrayList<String>(); if (attributeList != null) { for (Attribute attribute : attributeList) { attributeNamesList.add(attribute.getName()); } } return attributeNamesList; } @Override public Object convertToMappedInputEvent(Object obj) throws EventReceiverProcessingException { if (obj instanceof Event) { Event event = (Event) obj; Map<String, String> arbitraryMap = event.getArbitraryDataMap(); if (arbitraryMap != null && !arbitraryMap.isEmpty()) { return processArbitraryMap(event); } else if (inputDataTypeSpecificPositionMap != null) { Object[] outMetaAttrArray = new Object[outMetaSize]; Object[] outCorrelationAttrArray = new Object[outCorrelationSize]; Object[] outPayloadAttrArray = new Object[outPayloadSize]; // Construct input event as an array of attributes Object[] inEventArray = new Object[inputStreamSize]; int inEventArrayCount = 0; if (event.getMetaData() != null) { for (Object attribute : event.getMetaData()) { inEventArray[inEventArrayCount++] = attribute; } } if (event.getCorrelationData() != null) { for (Object attribute : event.getCorrelationData()) { inEventArray[inEventArrayCount++] = attribute; } } if (event.getPayloadData() != null) { for (Object attribute : event.getPayloadData()) { inEventArray[inEventArrayCount++] = attribute; } } // Finished construction of input event array int[] metaPositions = inputDataTypeSpecificPositionMap.get(InputDataType.META_DATA); for (int i = 0; i < metaPositions.length; i++) { outMetaAttrArray[i] = inEventArray[metaPositions[i]]; } int[] correlationPositions = inputDataTypeSpecificPositionMap.get(InputDataType.CORRELATION_DATA); for (int i = 0; i < correlationPositions.length; i++) { outCorrelationAttrArray[i] = inEventArray[correlationPositions[i]]; } int[] payloadPositions = inputDataTypeSpecificPositionMap.get(InputDataType.PAYLOAD_DATA); for (int i = 0; i < payloadPositions.length; i++) { outPayloadAttrArray[i] = inEventArray[payloadPositions[i]]; } return new Event(exportedStreamDefinition.getStreamId(), event.getTimeStamp(), outMetaAttrArray, outCorrelationAttrArray, outPayloadAttrArray); } else { return null; } } return null; } @Override public Object convertToTypedInputEvent(Object obj) throws EventReceiverProcessingException { if (obj instanceof Event) { return obj; } else { return null; } } @Override public Attribute[] getOutputAttributes() { WSO2EventInputMapping wso2EventInputMapping = (WSO2EventInputMapping) eventReceiverConfiguration.getInputMapping(); List<InputMappingAttribute> inputMappingAttributes = wso2EventInputMapping.getInputMappingAttributes(); return EventReceiverConfigurationHelper.getAttributes(inputMappingAttributes); } //TODO This method needs to be optimized for performance private Event processArbitraryMap(Event inEvent) { Map<String, String> arbitraryMap = inEvent.getArbitraryDataMap(); Object[] metaData, correlationData, payloadData; if (exportedStreamDefinition.getMetaData() != null) { metaData = new Object[exportedStreamDefinition.getMetaData().size()]; } else { metaData = new Object[0]; } if (exportedStreamDefinition.getCorrelationData() != null) { correlationData = new Object[exportedStreamDefinition.getCorrelationData().size()]; } else { correlationData = new Object[0]; } if (exportedStreamDefinition.getPayloadData() != null) { payloadData = new Object[exportedStreamDefinition.getPayloadData().size()]; } else { payloadData = new Object[0]; } for (int i = 0; i < metaData.length; i++) { Attribute metaAttribute = exportedStreamDefinition.getMetaData().get(i); String value = arbitraryMap.get(EventReceiverUtil.getMappedInputStreamAttributeName( metaAttribute.getName(), eventReceiverConfiguration.getInputMapping())); if (value != null) { Object attributeObj = EventReceiverUtil.getConvertedAttributeObject(value, metaAttribute.getType()); metaData[i] = attributeObj; } else { metaData[i] = inEvent.getMetaData()[i]; } } for (int i = 0; i < correlationData.length; i++) { Attribute correlationAttribute = exportedStreamDefinition.getCorrelationData().get(i); String value = arbitraryMap.get(EventReceiverUtil.getMappedInputStreamAttributeName( correlationAttribute.getName(), eventReceiverConfiguration.getInputMapping())); if (value != null) { Object attributeObj = EventReceiverUtil.getConvertedAttributeObject(value, correlationAttribute.getType()); correlationData[i] = attributeObj; } else { correlationData[i] = inEvent.getCorrelationData()[i]; } } for (int i = 0; i < payloadData.length; i++) { Attribute payloadAttribute = exportedStreamDefinition.getPayloadData().get(i); String value = arbitraryMap.get(EventReceiverUtil.getMappedInputStreamAttributeName( payloadAttribute.getName(), eventReceiverConfiguration.getInputMapping())); if (value != null) { Object attributeObj = EventReceiverUtil.getConvertedAttributeObject(value, payloadAttribute.getType()); payloadData[i] = attributeObj; } else { payloadData[i] = inEvent.getPayloadData()[i]; } } return new Event(inEvent.getStreamId(), inEvent.getTimeStamp(), metaData, correlationData, payloadData, arbitraryMap); } private enum InputDataType { META_DATA, CORRELATION_DATA, PAYLOAD_DATA } }