com.github.wuic.nut.dao.ssh.SshNutDao Maven / Gradle / Ivy
/*
* "Copyright (c) 2015 Capgemini Technology Services (hereinafter "Capgemini")
*
* License/Terms of Use
* Permission is hereby granted, free of charge and for the term of intellectual
* property rights on the Software, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to use, copy, modify and
* propagate free of charge, anywhere in the world, all or part of the Software
* subject to the following mandatory conditions:
*
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Any failure to comply with the above shall automatically terminate the license
* and be construed as a breach of these Terms of Use causing significant harm to
* Capgemini.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, PEACEFUL ENJOYMENT,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Capgemini shall not be used in
* advertising or otherwise to promote the use or other dealings in this Software
* without prior written authorization from Capgemini.
*
* These Terms of Use are subject to French law.
*
* IMPORTANT NOTICE: The WUIC software implements software components governed by
* open source software licenses (BSD and Apache) of which CAPGEMINI is not the
* author or the editor. The rights granted on the said software components are
* governed by the specific terms and conditions specified by Apache 2.0 and BSD
* licenses."
*/
package com.github.wuic.nut.dao.ssh;
import com.github.wuic.ApplicationConfig;
import com.github.wuic.NutType;
import com.github.wuic.ProcessContext;
import com.github.wuic.config.BooleanConfigParam;
import com.github.wuic.config.ConfigConstructor;
import com.github.wuic.config.IntegerConfigParam;
import com.github.wuic.config.ObjectConfigParam;
import com.github.wuic.config.StringConfigParam;
import com.github.wuic.exception.WuicException;
import com.github.wuic.nut.AbstractNut;
import com.github.wuic.nut.AbstractNutDao;
import com.github.wuic.nut.dao.NutDaoService;
import com.github.wuic.nut.Nut;
import com.github.wuic.nut.setter.ProxyUrisPropertySetter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.Future;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* A {@link com.github.wuic.nut.dao.NutDao} implementation for SSH accesses.
*
*
* @author Guillaume DROUET
* @version 1.6
* @since 0.3.1
*/
@NutDaoService
public class SshNutDao extends AbstractNutDao implements ApplicationConfig {
/**
* Default SSH port.
*/
private static final int DEFAULT_PORT = 22;
/**
* SFTP channel usage.
*/
private static final String SFTP_CHANNEL = "sftp";
/**
* Common exception message.
*/
private static final String CANNOT_LOAD_MESSAGE = "Can't load the file remotely with SSH FTP";
/**
* The logger.
*/
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* The SSH session.
*/
private Session session;
/**
* Path considered as regular expression or not.
*/
private Boolean regularExpression;
/**
*
* Builds a new instance.
*
*
* @param regex consider paths as regex or not
* @param host the host name
* @param p the port
* @param path default the path
* @param user the user name ({@code null} to skip the the authentication)
* @param pwd the password (will be ignored if user is {@code null})
* @param pollingInterval the interval for polling operations in seconds (-1 to deactivate)
* @param proxyUris the proxies URIs in front of the nut
* @param contentBasedVersionNumber {@code true} if version number is computed from nut content, {@code false} if based on timestamp
* @param computeVersionAsynchronously (@code true} if version number can be computed asynchronously, {@code false} otherwise
* @param fixedVersionNumber fixed version number, {@code null} if version number is computed from content or is last modification date
*/
@ConfigConstructor
public SshNutDao(@BooleanConfigParam(defaultValue = false, propertyKey = REGEX) final Boolean regex,
@StringConfigParam(defaultValue = "localhost", propertyKey = SERVER_DOMAIN) final String host,
@IntegerConfigParam(defaultValue = DEFAULT_PORT, propertyKey = SERVER_PORT) final int p,
@StringConfigParam(propertyKey = BASE_PATH, defaultValue = ".") final String path,
@BooleanConfigParam(defaultValue = false, propertyKey = BASE_PATH_AS_SYS_PROP) final Boolean basePathAsSysProp,
@StringConfigParam(defaultValue = "", propertyKey = LOGIN) final String user,
@StringConfigParam(defaultValue = "", propertyKey = PASSWORD) final String pwd,
@ObjectConfigParam(defaultValue = "", propertyKey = PROXY_URIS, setter = ProxyUrisPropertySetter.class) final String[] proxyUris,
@IntegerConfigParam(defaultValue = -1, propertyKey = POLLING_INTERVAL) final int pollingInterval,
@BooleanConfigParam(defaultValue = false, propertyKey = CONTENT_BASED_VERSION_NUMBER) final Boolean contentBasedVersionNumber,
@BooleanConfigParam(defaultValue = true, propertyKey = COMPUTE_VERSION_ASYNCHRONOUSLY) final Boolean computeVersionAsynchronously,
@StringConfigParam(defaultValue = "", propertyKey = ApplicationConfig.FIXED_VERSION_NUMBER) final String fixedVersionNumber) {
super(path, basePathAsSysProp, proxyUris, pollingInterval,
new VersionNumberStrategy(contentBasedVersionNumber, computeVersionAsynchronously, fixedVersionNumber));
regularExpression = regex;
final JSch jsch = new JSch();
try {
session = jsch.getSession(user, host, p);
session.setPassword(pwd);
final Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
} catch (JSchException je) {
throw new IllegalStateException("Can't open SSH session", je);
}
}
/**
*
* Connects the current session.
*
*
* @throws JSchException if connection fails
*/
private void connect() throws JSchException {
if (!session.isConnected()) {
session.connect();
}
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public List listNutsPaths(final String pattern) throws IOException {
ChannelSftp channel = null;
try {
connect();
if (regularExpression) {
channel = (ChannelSftp) session.openChannel(SFTP_CHANNEL);
channel.connect();
channel.cd(getBasePath());
final List list = channel.ls(pattern);
final List retval = new ArrayList(list.size());
for (final ChannelSftp.LsEntry entry : list) {
retval.add(entry.getFilename());
}
return retval;
} else {
return Arrays.asList(pattern);
}
} catch (JSchException je) {
WuicException.throwStreamException(new IOException(je));
return null;
} catch (SftpException se) {
WuicException.throwStreamException(new IOException(se));
return null;
} finally {
if (channel != null) {
channel.disconnect();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Nut accessFor(final String path, final NutType type, final ProcessContext processContext) throws IOException {
return new SshNut(path, type, getVersionNumber(path, processContext));
}
/**
* {@inheritDoc}
*/
@Override
protected Long getLastUpdateTimestampFor(final String path) throws IOException {
ChannelSftp channel = null;
try {
channel = (ChannelSftp) session.openChannel(SFTP_CHANNEL);
channel.connect();
channel.cd(getBasePath());
return (long) channel.stat(path).getMTime();
} catch (JSchException je) {
WuicException.throwStreamException(new IOException(je));
return null;
} catch (SftpException se) {
WuicException.throwStreamException(new IOException(CANNOT_LOAD_MESSAGE, se));
return null;
} finally {
if (channel != null) {
channel.disconnect();
}
}
}
/**
* {@inheritDoc}
*/
protected void finalize() throws Throwable {
// Disconnect the session if this instance is not referenced anymore
if (session.isConnected()) {
session.disconnect();
}
super.finalize();
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return String.format("%s with base path %s", getClass().getName(), getBasePath());
}
/**
* {@inheritDoc}
*/
@Override
public InputStream newInputStream(final String path, final ProcessContext processContext) throws IOException {
ChannelSftp channel = null;
try {
channel = open();
return channel.get(path);
} catch (SftpException se) {
WuicException.throwStreamException(new IOException("An SSH FTP error prevent remote file loading", se));
return null;
} finally {
if (channel != null) {
channel.disconnect();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Boolean exists(final String path, final ProcessContext processContext) throws IOException {
ChannelSftp channel = null;
boolean exception = false;
try {
channel = open();
} catch (SftpException se) {
exception = true;
WuicException.throwStreamException(new IOException("An SSH FTP error prevent remote file loading", se));
return false;
} finally {
if (exception) {
channel.disconnect();
}
}
try {
channel.lstat(path);
return Boolean.TRUE;
} catch (SftpException se) {
log.debug("A path does not exists", se);
return Boolean.FALSE;
} finally {
if (channel != null) {
channel.disconnect();
}
}
}
/**
*
* Open the returned channel and change directory to base path.
*
*
* @throws IOException if an I/O error occurs
* @throws SftpException if connection could not be opened
* @return the channel
*/
public ChannelSftp open() throws IOException, SftpException {
boolean exception = false;
ChannelSftp channel = null;
try {
connect();
channel = (ChannelSftp) session.openChannel(SFTP_CHANNEL);
channel.connect();
channel.cd(getBasePath());
exception = true;
return channel;
} catch (JSchException je) {
WuicException.throwStreamException(new IOException(CANNOT_LOAD_MESSAGE, je));
return null;
} finally {
if (exception) {
channel.disconnect();
}
}
}
/**
*
* Nut for SSH.
*
*
* @author Guillaume DROUET
* @version 1.0
* @since 0.5.0
*/
private final class SshNut extends AbstractNut {
/**
*
* Creates a new instance.
*
*
* @param name the name
* @param nt the {@link NutType}
* @param v the version number
*/
private SshNut(final String name, final NutType nt, final Future v) {
super(name, nt, v);
}
/**
* {@inheritDoc}
*/
@Override
public InputStream openStream() throws IOException {
ChannelSftp channel;
try {
connect();
channel = (ChannelSftp) session.openChannel(SFTP_CHANNEL);
channel.connect();
channel.cd(getBasePath());
return channel.get(getInitialName());
} catch (JSchException je) {
WuicException.throwStreamException(new IOException(CANNOT_LOAD_MESSAGE, je));
return null;
} catch (SftpException se) {
WuicException.throwStreamException(new IOException("An SSH FTP error prevent remote file loading", se));
return null;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy