All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.exactpro.sf.services.ntg.NTGMessageHelper Maven / Gradle / Ivy

There is a newer version: 3.4.260
Show newest version
/******************************************************************************
 * Copyright 2009-2018 Exactpro (Exactpro Systems Limited)
 *
 * 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.exactpro.sf.services.ntg;

import static com.exactpro.sf.common.messages.structures.StructureUtils.getAttributeValue;
import static com.exactpro.sf.services.ntg.NTGUtility.getTransactTimeAsDate;
import static com.exactpro.sf.util.DateTimeUtility.getMillisecond;

import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.exactpro.sf.common.codecs.AbstractCodec;
import com.exactpro.sf.common.messages.IMessage;
import com.exactpro.sf.common.messages.IMessageFactory;
import com.exactpro.sf.common.messages.MessageStructureWriter;
import com.exactpro.sf.common.messages.structures.IDictionaryStructure;
import com.exactpro.sf.common.messages.structures.IFieldStructure;
import com.exactpro.sf.common.messages.structures.IMessageStructure;
import com.exactpro.sf.common.util.EPSCommonException;
import com.exactpro.sf.services.IServiceContext;
import com.exactpro.sf.services.MessageHelper;
import com.exactpro.sf.services.ntg.exceptions.UndefinedMessageException;

public class NTGMessageHelper extends MessageHelper {
    private static final Logger LOGGER = LoggerFactory.getLogger(NTGMessageHelper.class);

    public static final String MESSAGE_HEADER = "MessageHeader";
    public static String FIELD_DIRTY_MSG_TYPE = "NTGMsgType";
    public static String FIELD_DIRTY_START = "DirtyStart";
    public static String FIELD_DIRTY_MSG_LEN = "DirtyMsgLen";

	public static final String FIELD_MESSAGE_LENGTH = "MessageLength";
	public static final String FIELD_START_OF_MESSAGE = "StartOfMessage";
    public static final int VALUE_START_OF_MESSAGE = 2;
    public static final String FIELD_TRANSACT_TIME = "TransactTime";
	public static final String MESSAGE_TYPE = "MessageType";

	public static final String MESSAGE_LOGON = "Logon";
	public static final String MESSAGE_HEARTBEAT = "Heartbeat";
	public static final String MESSAGE_REJECT = "Reject";
	public static final String ATTRIBUTE_MESSAGE_TYPE = "MessageType";

    public static final int PRECISION_4 = 4;
    public static final int PRECISION_8 = 8;
    
	private AbstractCodec codec;
    private Map metadata;

    private final class NTGMessageMetadata {
		public final Object messageType;
		public final Integer messageSize;

        public NTGMessageMetadata(Object messageType, Integer messageSize) {
			this.messageType = messageType;
			this.messageSize = messageSize;
		}

	}

    private class NTGSizeCalculator extends SimpleMessageStructureVisitor {

		private int messageSize;

		@Override
		public void visit(String fieldName, Object value, IFieldStructure fldStruct, boolean isDefault) {
            int length = getAttributeValue(fldStruct, NTGProtocolAttribute.Length.toString());
            int offset = getAttributeValue(fldStruct, NTGProtocolAttribute.Offset.toString());

            if(messageSize != offset) {
                throw new IllegalStateException();
            }

			messageSize = offset + length;
		}

		@Override
		public void visitCollection(String fieldName, List value, IFieldStructure fldStruct, boolean isDefault) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void visitMessage(String fieldName, IMessage message, IFieldStructure complexField,
				IFieldStructure fldStruct, boolean isDefault) {

            NTGSizeCalculator visitor = new NTGSizeCalculator();
            MessageStructureWriter.WRITER.traverse(visitor, complexField.getFields());

            Integer length = getAttributeValue(fldStruct, NTGProtocolAttribute.Length.toString());

			if (length != null && visitor.getMessageSize() != length) {
				throw new IllegalStateException();
			}
			
			messageSize += visitor.getMessageSize();
		}

		@Override
		public void visitMessageCollection(String fieldName, List message, IFieldStructure complexField, boolean isDefault) {
			throw new UnsupportedOperationException();
		}

		public int getMessageSize() {
			return messageSize;
		}

	}

    @Override
    public void init(IMessageFactory messageFactory, IDictionaryStructure messageDictionary) {
		super.init(messageFactory, messageDictionary);

        metadata = new HashMap();

        for(IMessageStructure structure : messageDictionary.getMessages().values()) {
            // part of validation is done in NTGVisitorBase
            // part of message header creation is done in NTGVisitorBase
			
            Byte messageTypeCode = getAttributeValue(structure, ATTRIBUTE_MESSAGE_TYPE); //Fields block can not contain MessageType

			if (messageTypeCode != null) { // skip headers...
				// calculate message sizes
                NTGSizeCalculator visitor = new NTGSizeCalculator();
                MessageStructureWriter.WRITER.traverse(visitor, structure);
                Integer messageSize = visitor.getMessageSize() - 3; // Don't include 'StartOfMessage' and 'MessageLength'
                
                try {
                    String messageType = NTGVisitorBase.DECODER.get().decode(ByteBuffer.wrap(new byte[] { messageTypeCode })).toString().trim();
                    metadata.put(structure.getName(), new NTGMessageMetadata(messageType, messageSize));
                } catch (CharacterCodingException e) {
                    throw new EPSCommonException("Problem with decoding the messageTypeCode = \"" + messageTypeCode + "\"", e);
                }
			}
		}
	}

	@Override
	public synchronized AbstractCodec getCodec(IServiceContext serviceContext) {
		if (codec == null) {
            codec = new NTGCodec();
			codec.init(serviceContext, null, getMessageFactory(), getDictionaryStructure());
		}
		return codec;
	}

	@Override
	public IMessage prepareMessageToEncode(IMessage message, Map params) {
		// AML3 - header can be filled like repeating group.
		IMessage header = (IMessage) message.getField(MESSAGE_HEADER);
        NTGMessageMetadata m = getMetadata(message.getName());
        if(header == null) {
            header = getMessageFactory().createMessage(MESSAGE_HEADER, getNamespace());
            // add header to message
            message.addField(MESSAGE_HEADER, header);
        }

        if (!header.isFieldSet(FIELD_MESSAGE_LENGTH)) {
            // special case: handle AML2 actions that doesn't sets
            // MessageLength field
            header.addField(FIELD_MESSAGE_LENGTH, m.messageSize);
        }
        if (!header.isFieldSet(FIELD_START_OF_MESSAGE)) {
            header.addField(FIELD_START_OF_MESSAGE, VALUE_START_OF_MESSAGE);
        }
        if (!header.isFieldSet(MESSAGE_TYPE)) {
            header.addField(MESSAGE_TYPE, m.messageType);
        }


		if (params != null) {
            // AML2 - header filled by actions. Dirty AML2 uses "#nativemsgtype", "#dirtystart", "#dirtymsglen" to override header's fields
		    String value = params.get(FIELD_DIRTY_MSG_LEN);
		    if (value != null) {
                header.addField(FIELD_MESSAGE_LENGTH, Integer.valueOf(value));
		    }
		    
		    value = params.get(FIELD_DIRTY_MSG_TYPE);
            if (value != null) {
                header.addField(MESSAGE_TYPE, value);
            }
            
            value = params.get(FIELD_DIRTY_START);
            if (value != null) {
                header.addField(FIELD_START_OF_MESSAGE, Integer.valueOf(value));
            }
		}
		return message;
	}

    private NTGMessageMetadata getMetadata(String messageName) {
        NTGMessageMetadata m = metadata.get(messageName);
		if (m == null) {
			throw new UndefinedMessageException(String.format("namespace=[%s] name=[%s]", getNamespace(), messageName));
		}
		return m;
	}

    @Override
    public long getSenderTime(IMessage message) {
        try {
            String transactTime = message.getField(FIELD_TRANSACT_TIME);

            if(transactTime != null) {
                return getMillisecond(getTransactTimeAsDate(transactTime));
            }
        } catch(Exception e) {
            LOGGER.error("Failed to retrieve timestamp from message: {}", message, e);
        }

        return super.getSenderTime(message);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy