com.siemens.sw360.fossology.ssh.JSchSessionProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.siemens.sw360.fossology.ssh.JSchSessionProvider.java

Source

/*
 * Copyright Siemens AG, 2015. Part of the SW360 Portal Project.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package com.siemens.sw360.fossology.ssh;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.siemens.sw360.datahandler.thrift.SW360Exception;
import com.siemens.sw360.fossology.config.FossologySettings;
import com.siemens.sw360.fossology.ssh.keyrepo.FossologyHostKeyRepository;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.Optional;

import static org.apache.log4j.Logger.getLogger;

@Component
public class JSchSessionProvider implements DisposableBean {
    private static final Logger log = getLogger(JSchSessionProvider.class);

    static {
        JSch.setLogger(new JSchLogForwarder());
        JSch.setConfig("StrictHostKeyChecking", "yes");
    }

    private static final JSch J_SCH = new JSch();

    private final FossologyHostKeyRepository fossologyHostKeyRepository;
    private final String userName;
    private final String hostName;
    private final int hostPort;
    private final ConcurrentLinkedQueue<Session> sessions;

    @Autowired
    public JSchSessionProvider(FossologySettings fossologySettings,
            FossologyHostKeyRepository fossologyHostKeyRepository) {
        this.fossologyHostKeyRepository = fossologyHostKeyRepository;

        userName = fossologySettings.getFossologySshUsername();
        hostName = fossologySettings.getFossologyHost();
        hostPort = fossologySettings.getFossologyPort();

        addIdentity(userName, fossologySettings.getFossologyPrivateKey());
        sessions = new ConcurrentLinkedQueue<>();
    }

    @Override
    public void destroy() throws Exception {
        for (Session session : sessions) {
            doCloseSession(session);
        }
    }

    private void addIdentity(String userName, byte[] privateKey) {
        synchronized (J_SCH) {
            try {
                if (!J_SCH.getIdentityNames().contains(userName)) {
                    J_SCH.addIdentity(userName, privateKey, null, null);
                }
            } catch (JSchException e) {
                log.error("cannot set Identity for " + userName, e);
            }
        }
    }

    private Optional<Session> pollCachedSession() {
        Session session = sessions.poll();
        if (session != null && session.isConnected()) {
            return Optional.of(session);
        } else {
            return Optional.empty();
        }
    }

    public Session getSession(int connectionTimeout) throws SW360Exception {
        Optional<Session> session = pollCachedSession();
        if (session.isPresent()) {
            return session.get();
        } else {
            return doGetSession(connectionTimeout);
        }
    }

    public void closeSession(Session session) {
        if (session == null) {
            return;
        }
        if (session.isConnected()) {
            if (sessions.size() < 5) { // minor race condition, not a problem
                sessions.add(session);
            } else {
                doCloseSession(session);
            }
        }
    }

    private Session doGetSession(int connectionTimeout) throws SW360Exception {
        synchronized (J_SCH) {
            try {
                Session session = J_SCH.getSession(userName, hostName, hostPort);
                session.setHostKeyRepository(fossologyHostKeyRepository);
                session.connect(connectionTimeout);
                return session;
            } catch (JSchException e) {
                String serverString = getServerString();
                log.error("cannot connect to fossology server: " + serverString, e);
                throw new SW360Exception("cannot connect to Fossology Server");
            }
        }
    }

    private void doCloseSession(Session session) {
        if (session != null && session.isConnected()) {
            session.disconnect();
        }
    }

    public String getServerString() {
        return userName + "@[" + hostName + "]:[" + hostPort + "]";
    }

    private static class JSchLogForwarder implements com.jcraft.jsch.Logger {
        @Override
        public boolean isEnabled(int level) {
            return log.isEnabledFor(Level.toLevel(level));
        }

        @Override
        public void log(int level, String message) {
            log.log(Level.toLevel(level), message);
        }
    }
}