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

com.exactpro.sf.services.tcpip.TCPIPProxy 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.tcpip;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.exactpro.sf.aml.script.actions.WaitAction;
import com.exactpro.sf.common.codecs.AbstractCodec;
import com.exactpro.sf.common.codecs.CodecFactory;
import com.exactpro.sf.common.impl.messages.DefaultMessageFactory;
import com.exactpro.sf.common.messages.IMessage;
import com.exactpro.sf.common.messages.IMessageFactory;
import com.exactpro.sf.common.messages.structures.IDictionaryStructure;
import com.exactpro.sf.common.services.ServiceInfo;
import com.exactpro.sf.common.services.ServiceName;
import com.exactpro.sf.common.util.EPSCommonException;
import com.exactpro.sf.configuration.IDataManager;
import com.exactpro.sf.configuration.IDictionaryManager;
import com.exactpro.sf.configuration.ILoggingConfigurator;
import com.exactpro.sf.configuration.Rules;
import com.exactpro.sf.configuration.suri.SailfishURI;
import com.exactpro.sf.scriptrunner.ScriptRunException;
import com.exactpro.sf.scriptrunner.actionmanager.actioncontext.IActionContext;
import com.exactpro.sf.services.IInitiatorService;
import com.exactpro.sf.services.IServiceContext;
import com.exactpro.sf.services.IServiceHandler;
import com.exactpro.sf.services.IServiceMonitor;
import com.exactpro.sf.services.IServiceSettings;
import com.exactpro.sf.services.ISession;
import com.exactpro.sf.services.ITaskExecutor;
import com.exactpro.sf.services.ServiceException;
import com.exactpro.sf.services.ServiceStatus;
import com.exactpro.sf.services.WrapperNioSocketAcceptor;
import com.exactpro.sf.services.WrapperNioSocketConnector;
import com.exactpro.sf.services.mina.MINASession;
import com.exactpro.sf.services.util.ServiceUtil;
import com.exactpro.sf.storage.IMessageStorage;

public abstract class TCPIPProxy implements IInitiatorService
{
    private final Logger logger = LoggerFactory.getLogger(ILoggingConfigurator.getLoggerName(this));

	private Rules rules;
	private volatile ServiceStatus curStatus;
	protected TCPIPProxySettings settings;

	protected IMessageStorage storage;
	protected WrapperNioSocketConnector connector;
	protected IServiceHandler handler;
	protected ILoggingConfigurator logConfigurator;

	private ServiceName serviceName;
    private ServiceInfo serviceInfo;
	private WrapperNioSocketAcceptor acceptor;
	private IoSession session;
    private boolean haveConnection;
	private Class codecClass;
	private IServiceMonitor monitor;
    private final Map sessions = Collections.synchronizedMap(new HashMap());
	private IServiceContext serviceContext;
	private ITaskExecutor taskExecutor;
	private IDataManager dataManager;
    protected IDictionaryStructure dictionary;
    protected IMessageFactory factory;

	public TCPIPProxy()
	{
		curStatus = ServiceStatus.CREATED;

		this.settings = null;

		this.session = null;

		this.handler = null;

		this.codecClass = null;

		this.rules = null;

	}

	@Override
	public void init(IServiceContext serviceContext,
            IServiceMonitor serviceMonitor,
            IServiceHandler handler,
            IServiceSettings serviceSettings,
            ServiceName serviceName)
	{
		try {
			changeStatus(ServiceStatus.INITIALIZING, "Service initializing", null);

			this.serviceName = Objects.requireNonNull(serviceName, "'Service name' parameter");

			this.serviceContext = Objects.requireNonNull(serviceContext, "'Service context' parameter");

			this.storage = Objects.requireNonNull(this.serviceContext.getMessageStorage(), "'Message storage' parameter");

			this.handler = Objects.requireNonNull(handler, "'Service handler' parameter");

            if(serviceSettings == null) {
                throw new NullPointerException("settings");
            }

            if(serviceSettings instanceof TCPIPProxySettings) {
                this.settings = (TCPIPProxySettings)serviceSettings;
            } else {
                throw new ServiceException("Incorrect class of settings has been passed to init " + serviceSettings.getClass());
            }

			this.monitor = serviceMonitor;

			this.logConfigurator = Objects.requireNonNull(this.serviceContext.getLoggingConfigurator(), "'Logging configurator' parameter");

			this.dataManager = Objects.requireNonNull(this.serviceContext.getDataManager(), "'Data manager' parameter");

			this.taskExecutor = this.serviceContext.getTaskExecutor();

            this.serviceInfo = Objects.requireNonNull(serviceContext.lookupService(serviceName), "serviceInfo cannot be null");

			if(StringUtils.isEmpty(settings.getCodecClassName())){
				throw new NullPointerException("Codec class name");
			}

			try {
                this.codecClass = getClass().getClassLoader().loadClass(settings.getCodecClassName()).asSubclass(AbstractCodec.class);
			} catch (ClassNotFoundException e) {
				changeStatus(ServiceStatus.ERROR, "Error while init", e);
				logger.error(e.getMessage(), e);
				throw new ScriptRunException("Could not find codec class [" + settings.getCodecClassName() + "]", e);
			}

            if(settings.isChangeTags() && (settings.getRulesAlias() != null)) {
				Unmarshaller u = null;
				JAXBContext jc = null;

				try {

					jc = JAXBContext.newInstance(new Class[]{Rules.class});
					u = jc.createUnmarshaller();
					InputStream rulesAliasIS = dataManager.getDataInputStream(settings.getRulesAlias());
					JAXBElement root = u.unmarshal(new StreamSource(rulesAliasIS), Rules.class);
					this.rules = root.getValue();

				} catch (JAXBException e) {
					logger.error(e.getMessage(), e);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}

            SailfishURI dictionaryName = Objects.requireNonNull(settings.getDictionaryName(), "dictionary name cannot be null");

            this.dictionary = this.serviceContext.getDictionaryManager().getDictionary(dictionaryName);
            this.factory = this.serviceContext.getDictionaryManager().getMessageFactory(dictionaryName);

            internalInit(serviceName, this.serviceContext.getDictionaryManager(), handler, serviceSettings, storage, serviceMonitor, logConfigurator, taskExecutor, dataManager);

			changeStatus(ServiceStatus.INITIALIZED, "Service initialized", null);
		} catch (RuntimeException e){
			changeStatus(ServiceStatus.ERROR, "Error while initialize", e);
			throw e;
		}

	}

    public void reinit(IServiceSettings serviceSettings) {
		TCPIPProxySettings newSettings;
		if (serviceSettings instanceof TCPIPProxySettings) {
			newSettings = (TCPIPProxySettings) serviceSettings;
		} else {
			throw new ServiceException("Incorrect class of settings has been passed to init " + serviceSettings.getClass());
		}

        if(newSettings.isChangeTags() && (newSettings.getRulesAlias() != null)) {
			try {
				JAXBContext jc = JAXBContext.newInstance(new Class[]{Rules.class});
				Unmarshaller u = jc.createUnmarshaller();
				InputStream rulesAliasIS = dataManager.getDataInputStream(newSettings.getRulesAlias());
				JAXBElement root = u.unmarshal(new StreamSource(rulesAliasIS),Rules.class);
				this.rules = root.getValue();
			} catch (Exception e) {
				disconnect();
				dispose();
				changeStatus(ServiceStatus.ERROR, "Error while reiniting", e);
				throw new EPSCommonException(e);
			}
		}
	}

    protected abstract void internalInit(ServiceName serviceName,
            IDictionaryManager dictionaryManager,
            IServiceHandler handler,
            IServiceSettings settings,
            IMessageStorage storage,
            IServiceMonitor serviceMonitor,
            ILoggingConfigurator logConfigurator,
            ITaskExecutor taskExecutor,
            IDataManager dataManager);

	@Override
	public void start() {

        logConfigurator.createAndRegister(getServiceName(), this);

		changeStatus(ServiceStatus.STARTING, "Service starting", null);

		this.connector = new WrapperNioSocketConnector(taskExecutor);
		this.acceptor = new WrapperNioSocketAcceptor(taskExecutor);

        connector.setConnectTimeoutMillis(settings.getTimeout());
		IMessageFactory msgFactory = DefaultMessageFactory.getFactory();

        CodecFactory codecFactory = new CodecFactory(serviceContext, msgFactory, null, codecClass, settings);

        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(codecFactory));
        acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(codecFactory));

		IProxyIoHandler clientSideIoHandler = getProxyIoHandler();
        clientSideIoHandler.setServiceInfo(serviceInfo);
		acceptor.setHandler(clientSideIoHandler);

		try {
			connect(0);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			changeStatus(ServiceStatus.ERROR, "Error while starting", e);
		}

		changeStatus(ServiceStatus.STARTED, "Service started", null);

	}

	protected  abstract IProxyIoHandler getProxyIoHandler();

	@Override
	public String getName() {
		return serviceName.toString();
	}

	@Override
	public ServiceName getServiceName() {
		return serviceName;
	}

	@Override
	public void dispose() {

		changeStatus(ServiceStatus.DISPOSING, "Service disposing", null);

        if(connector != null) {
            connector.dispose();
			this.connector = null;
		}
        if(acceptor != null) {
            acceptor.dispose();
			this.acceptor = null;
		}

		changeStatus(ServiceStatus.DISPOSED, "Service disposed", null);

		if(logConfigurator != null) {
            logConfigurator.destroyAppender(getServiceName());
		}

	}


	@Override
	public IServiceHandler getServiceHandler()
	{
        return handler;
	}


	@Override
	public ISession getSession() {

		//List list = new ArrayList();

		//for (ISession session : this.sessions.values()) {
		//	list.add(session);
		//}
        return !sessions.isEmpty() ? sessions.get(session) : null;
    }

	public ISession getSession(IoSession key) {
		return sessions.get(key);
	}

	public boolean connect(long timeOut) throws IOException
	{
        if(haveConnection) {
			return true;
		}

        acceptor.bind(new InetSocketAddress(settings.getListenPort()));

		this.haveConnection = true;
        return haveConnection;
	}

	public boolean disconnect()
	{
        if(haveConnection) {
            session.close(true);
			this.haveConnection = false;
		}
		return true;
	}

	@Override
	public ServiceStatus getStatus()
	{
        return curStatus;
	}

	protected void changeStatus(ServiceStatus status, String message, Throwable e) {
		this.curStatus = status;
		ServiceUtil.changeStatus(this, monitor, status, message, e);
	}

	public void addSession(IoSession key, MINASession value)
	{
		this.session = key;
        sessions.put(key, value);
	}

	public Rules getRules() {
		return rules;
	}

	public void setRules(Rules rules) {
		this.rules = rules;
	}

	@Override
    public TCPIPProxySettings getSettings() {
		return settings;
	}

	public void setSettings(TCPIPProxySettings settings) {
		this.settings = settings;
	}

	@Override
	public void setServiceHandler(IServiceHandler handler) {
		// TODO Auto-generated method stub

	}

	@Override
	public String toString() {
		return new ToStringBuilder(this).append("name", serviceName).toString();
	}

	@Override
	public void connect() throws Exception
	{
	}

	@Override
    public IMessage receive(IActionContext actionContext, IMessage msg) throws InterruptedException {
		return (IMessage) WaitAction.waitForMessage(actionContext, msg, !msg.getMetaData().isAdmin());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy