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

com.exactpro.sf.services.fast.FASTCodec Maven / Gradle / Ivy

There is a newer version: 3.3.241
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.fast;

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.MsgMetaData;
import com.exactpro.sf.common.messages.structures.IDictionaryStructure;
import com.exactpro.sf.common.messages.structures.IMessageStructure;
import com.exactpro.sf.common.util.ICommonSettings;
import com.exactpro.sf.configuration.IDataManager;
import com.exactpro.sf.configuration.suri.SailfishURI;
import com.exactpro.sf.connectivity.mina.net.IoBufferWithAddress;
import com.exactpro.sf.services.IServiceContext;
import com.exactpro.sf.services.fast.converter.ConverterException;
import com.exactpro.sf.services.fast.converter.FastToIMessageConverter;
import com.exactpro.sf.services.fast.converter.IMessageToFastConverter;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.openfast.Context;
import org.openfast.IntegerValue;
import org.openfast.Message;
import org.openfast.MessageOutputStream;
import org.openfast.template.TemplateRegistry;
import org.openfast.template.type.codec.TypeCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

import static com.exactpro.sf.common.messages.structures.StructureUtils.getAttributeValue;

public class FASTCodec extends AbstractCodec {

	private static final String INPUT_CONTEXT_ATTR_NAME = "FAST_INPUT_CONTEXT";
	private static final String OUTPUT_CONTEXT_ATTR_NAME = "FAST_OUTPUT_CONTEXT";

	static final Logger logger = LoggerFactory.getLogger(FASTCodec.class);

	private IServiceContext serviceContext;
	private IDictionaryStructure msgDictionary;
	private FastToIMessageConverter converter;
	private FASTCodecSettings settings;
	private TemplateRegistry registry;
	private IMessageToFastConverter iMsgToFastConverter;
	private FastToIMessageDecoder decoder;

	@Override
	public void init(
			IServiceContext serviceContext,
			ICommonSettings settings,
			IMessageFactory msgFactory, IDictionaryStructure dictionary) {
        super.init(serviceContext, settings, msgFactory, dictionary);

        this.serviceContext = Objects.requireNonNull(serviceContext, "'Service context' parameter cannot be null");
        this.msgDictionary = Objects.requireNonNull(dictionary, "'dictionary' parameter cannot be null");
        String fastTemplate = Objects.requireNonNull(getAttributeValue(dictionary, FASTMessageHelper.TEMPLATE_ATTRIBYTE), "'Template attribute' parameter");
        this.settings = (FASTCodecSettings)Objects.requireNonNull(settings, "'settings' parameter cannot be null");
        SailfishURI dictionaryName = Objects.requireNonNull(this.settings.getDictionaryName(), "'Dictionary name' parameter");
        IDataManager dataManager = Objects.requireNonNull(this.serviceContext.getDataManager(), "'Data manager' parameter");
        FastTemplateLoader templateLoader = new FastTemplateLoader();
        this.registry = templateLoader.loadFastTemplates(dataManager, dictionaryName.getPluginAlias(), fastTemplate);
        this.converter = new FastToIMessageConverter(msgFactory, msgDictionary);
        this.decoder = new FastToIMessageDecoder(converter, this.settings.getSkipInitialByteAmount());
    }

	private TemplateRegistry getRegistry() {
		return registry;
	}

	protected Context createFastContext() {
		Context context = new FASTContext();

		context.setTemplateRegistry(getRegistry());
		context.setTraceEnabled(true);
		context.setDecodeTrace(new LoggingTrace());
		return context;
	}

	protected FASTCodecSettings getSettings() {
		return settings;
	}

	@Override
	protected boolean doDecodeInternal(
			IoSession session,
			IoBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		if (!in.hasRemaining()) {
			return false;
		}
		int position = in.position();
		try {
			if (doRealDecode(session, in, out)) {
				return true;
			}
		} catch (Exception e) {
			logger.error("Can not decode message", e);
		}
		in.position(position);
		return false;
	}

	@Override
	public void decode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		if (!session.getTransportMetadata().hasFragmentation()) {
            if(settings.isResetContextAfterEachUdpPacket()) {
                getInputContext(session).reset();
            }
		}
		super.decode(session, in, out);
	}

	private boolean doRealDecode(
			IoSession session,
			IoBuffer in,
			ProtocolDecoderOutput out) throws IOException, ConverterException {
        int startPosition = in.position();
        byte[] data = new byte[in.remaining()];
        in.get(data);
        DecodeResult decodeResult = decoder.decode(data, getInputContext(session), settings.isLengthPresent());
        boolean isSuccessDecoded = decodeResult.isSuccess();
        if (isSuccessDecoded) {
            IMessage decodedMessage = decodeResult.getDecodedMessage();
            fillMessageMetadata(session, in, decodedMessage);
            out.write(decodedMessage);
        }
        in.position(startPosition + decodeResult.getProcessedDataLength());
        return isSuccessDecoded;
	}

	private void fillMessageMetadata(
			IoSession session,
			IoBuffer in,
			IMessage imsg) {
        IMessageStructure msgStructure = msgDictionary.getMessages().get(imsg.getName());
        Boolean isAdmin = getAttributeValue(msgStructure, "IsAdmin");
		if (isAdmin == null) {
			isAdmin = false;
		}

		MsgMetaData metaData = imsg.getMetaData();
		metaData.setAdmin(isAdmin);
		//metaData.setToService(this.serviceName);

        String packetAddress = in instanceof IoBufferWithAddress ? ((IoBufferWithAddress)in).getAddress() : session.getRemoteAddress().toString();

        metaData.setFromService(packetAddress);
	}


	private Context getInputContext(IoSession session) {
		Context inputContext = (Context) session.getAttribute(INPUT_CONTEXT_ATTR_NAME);
		if (inputContext == null) {
			inputContext = createFastContext();
			session.setAttribute(INPUT_CONTEXT_ATTR_NAME, inputContext);
		}
		return inputContext;
	}

	private Context getOutputContext(IoSession session) {
		Context outputContext = (Context) session.getAttribute(OUTPUT_CONTEXT_ATTR_NAME);
		if (outputContext == null) {
			outputContext = createFastContext();
			session.setAttribute(OUTPUT_CONTEXT_ATTR_NAME, outputContext);
		}
		return outputContext;
	}

	@Override
	public void encode(
			IoSession session,
			Object message,
			ProtocolEncoderOutput out) throws Exception {

		IMessageToFastConverter converter = getIMessageToFastConverter();
		IMessage iMsg = (IMessage) message;

        Message fastMsg = converter.convert(iMsg);
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		Context oc = getOutputContext(session);
		MessageOutputStream msgOutStream = new MessageOutputStream(os, oc);
		msgOutStream.writeMessage(fastMsg);
		byte[] outputdata = os.toByteArray();
		byte[] blockHeader = TypeCodec.UINT.encode(new IntegerValue(outputdata.length));

		byte[] result = Arrays.copyOf(blockHeader, blockHeader.length + outputdata.length);
		System.arraycopy(outputdata, 0, result, blockHeader.length, outputdata.length);

		out.write(IoBuffer.wrap(result));
		if (settings.isResetContextAfterEachUdpPacket()) {
			oc.reset();
		}
	}

	private IMessageToFastConverter getIMessageToFastConverter() {
		if (iMsgToFastConverter == null) {
            IDictionaryStructure dictionary = msgDictionary;
			iMsgToFastConverter = new IMessageToFastConverter(dictionary, getRegistry());
		}
		return iMsgToFastConverter;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy