X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.akb%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fakb%2Fcore%2FAkbServiceImpl.java;h=ba7b6cc0470273a88bd118ce77588c8320f87d6f;hb=ee9455a85f291bd41955aae4ab406f381b5dfd9a;hp=02ccdc6f6f508a4203f3a3428c8fac0b4b518890;hpb=c5a5cb9a47fdafcc95f1b8902f31b62a0e6a9674;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java index 02ccdc6f6..ba7b6cc04 100644 --- a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java +++ b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java @@ -1,27 +1,49 @@ package org.argeo.slc.akb.core; +import java.net.URI; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLFeatureNotSupportedException; import java.util.Map; import javax.annotation.Resource; +import javax.jcr.Node; +import javax.jcr.Property; import javax.jcr.Repository; +import javax.jcr.RepositoryException; import javax.jcr.Session; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.slc.SlcException; import org.argeo.slc.akb.AkbException; import org.argeo.slc.akb.AkbNames; +import org.argeo.slc.akb.AkbService; +import org.argeo.slc.akb.AkbTypes; +import org.argeo.slc.jsch.SimpleUserInfo; +import org.argeo.util.security.Keyring; + +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.JSch; /** * Concrete access to akb services. It provides among other an initialized * environment */ -public class AkbServiceImpl implements AkbNames { +public class AkbServiceImpl implements AkbService, AkbNames { private final static Log log = LogFactory.getLog(AkbServiceImpl.class); /* DEPENDENCY INJECTION */ private Repository repository; + private Keyring keyring; + // Populate the repository in a demo context. private Map demoData = null; @@ -31,6 +53,10 @@ public class AkbServiceImpl implements AkbNames { * receive/provide data. */ public void init() { + // JDBC drivers + // TODO make it configurable + initJdbcDriver("org.postgresql.Driver"); + Session adminSession = null; try { adminSession = repository.login(); @@ -55,19 +81,263 @@ public class AkbServiceImpl implements AkbNames { } finally { JcrUtils.logoutQuietly(adminSession); } - // log.info("AKB service has been initialized."); + } + + protected Boolean initJdbcDriver(String driver) { + try { + Class.forName(driver); + return true; + } catch (ClassNotFoundException e) { + if (log.isDebugEnabled()) + log.debug("Cannot load JDBC driver : " + driver + ", " + + e.getMessage()); + return false; + } } /** Clean shutdown of the backend. */ public void destroy() { - // Do nothing } - /** Expose injected repository */ - public Repository getRepository() { - return repository; + @Override + public Node createAkbTemplate(Node parentNode, String name) + throws RepositoryException { + String connectorParentName = "Connectors"; + String itemsParentName = "Items"; + + Node newTemplate = parentNode.addNode(name, AkbTypes.AKB_ENV_TEMPLATE); + newTemplate.setProperty(Property.JCR_TITLE, name); + + Node connectorParent = newTemplate.addNode( + AkbTypes.AKB_CONNECTOR_FOLDER, AkbTypes.AKB_CONNECTOR_FOLDER); + connectorParent.setProperty(Property.JCR_TITLE, connectorParentName); + + Node itemsParent = newTemplate.addNode(AkbTypes.AKB_ITEM_FOLDER, + AkbTypes.AKB_ITEM_FOLDER); + itemsParent.setProperty(Property.JCR_TITLE, itemsParentName); + + return newTemplate; } + // /////////////////////////////////////// + // / CONNECTORS + + public boolean testConnector(Node connectorNode) { + try { + if (connectorNode.isNodeType(AkbTypes.AKB_JDBC_CONNECTOR)) { + String connectorUrl = connectorNode.getProperty( + AKB_CONNECTOR_URL).getString(); + String connectorUser = connectorNode.getProperty( + AKB_CONNECTOR_USER).getString(); + + String pwdPath = getPasswordPath(connectorNode); + char[] pwd = keyring.getAsChars(pwdPath); + DriverManager.getConnection(connectorUrl, connectorUser, + new String(pwd)); + savePassword(connectorNode.getSession(), pwdPath, pwd); + return true; + } else if (connectorNode.isNodeType(AkbTypes.AKB_SSH_CONNECTOR)) { + String connectorUrl = connectorNode.getProperty( + AKB_CONNECTOR_URL).getString(); + String connectorUser = connectorNode.getProperty( + AKB_CONNECTOR_USER).getString(); + String pwdPath = getPasswordPath(connectorNode); + char[] pwd = keyring.getAsChars(pwdPath); + + URI url = new URI(connectorUrl); + String host = url.getHost(); + int port = url.getPort(); + if (port == -1) + port = 22; + JSch jsch = new JSch(); + com.jcraft.jsch.Session sess = jsch.getSession(connectorUser, + host, port); + SimpleUserInfo userInfo = new SimpleUserInfo(); + userInfo.setPassword(new String(pwd)); + sess.setUserInfo(userInfo); + sess.connect(); + sess.disconnect(); + + savePassword(connectorNode.getSession(), pwdPath, pwd); + return true; + } else { + throw new SlcException("Unsupported connector " + connectorNode); + } + } catch (Exception e) { + throw new SlcException("Cannot test connection", e); + } + } + + /** + * Opens a new connection each time. All resources must be cleaned by + * caller. + */ + public PreparedStatement prepareJdbcQuery(Node node) { + PreparedStatement statement = null; + try { + if (node.isNodeType(AkbTypes.AKB_JDBC_QUERY)) { + String sqlQuery = node.getProperty(AKB_QUERY_TEXT).getString(); + + String connectorPath = node.getProperty(AKB_USED_CONNECTOR) + .getString(); + Node connectorNode = node.getSession().getNode(connectorPath); + String connectorUrl = connectorNode.getProperty( + AKB_CONNECTOR_URL).getString(); + String connectorUser = connectorNode.getProperty( + AKB_CONNECTOR_USER).getString(); + + String pwdPath = getPasswordPath(connectorNode); + // String pwdPath = connectorNode.getPath() + '/' + // + ArgeoNames.ARGEO_PASSWORD; + char[] pwd = keyring.getAsChars(pwdPath); + Connection connection = DriverManager.getConnection( + connectorUrl, connectorUser, new String(pwd)); + try { + statement = connection.prepareStatement(sqlQuery, + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + } catch (SQLFeatureNotSupportedException e) { + log.warn("Scroll not supported for " + connectorUrl); + statement = connection.prepareStatement(sqlQuery); + } + } else { + throw new SlcException("Unsupported node " + node); + } + return statement; + } catch (Exception e) { + throw new SlcException("Cannot execute test JDBC query on " + node, + e); + } + } + + public String executeCommand(Node node) { + try { + String command = node.getProperty(AkbNames.AKB_COMMAND_TEXT) + .getString(); + + String connectorPath = node.getProperty(AKB_USED_CONNECTOR) + .getString(); + Node connectorNode = node.getSession().getNode(connectorPath); + String connectorUrl = connectorNode.getProperty(AKB_CONNECTOR_URL) + .getString(); + String connectorUser = connectorNode + .getProperty(AKB_CONNECTOR_USER).getString(); + String pwdPath = getPasswordPath(connectorNode); + char[] pwd = keyring.getAsChars(pwdPath); + + URI url = new URI(connectorUrl); + String host = url.getHost(); + int port = url.getPort(); + if (port == -1) + port = 22; + JSch jsch = new JSch(); + com.jcraft.jsch.Session sess = jsch.getSession(connectorUser, host, + port); + SimpleUserInfo userInfo = new SimpleUserInfo(); + userInfo.setPassword(new String(pwd)); + sess.setUserInfo(userInfo); + sess.connect(); + + sess.openChannel("exec"); + final ChannelExec channel = (ChannelExec) sess.openChannel("exec"); + channel.setCommand(command); + + channel.setInputStream(null); + channel.setXForwarding(false); + channel.setAgentForwarding(false); + channel.setErrStream(null); + + channel.connect(); + + String output = IOUtils.toString(channel.getInputStream()); + channel.disconnect(); + + sess.disconnect(); + + return output; + } catch (Exception e) { + throw new SlcException("Cannot execute command", e); + } + + } + + public String retrieveFile(Node node) { + try { + String filePath = node.getProperty(AkbNames.AKB_FILE_PATH) + .getString(); + String command = "cat " + filePath; + + // TODO do a proper scp + String connectorPath = node.getProperty(AKB_USED_CONNECTOR) + .getString(); + Node connectorNode = node.getSession().getNode(connectorPath); + String connectorUrl = connectorNode.getProperty(AKB_CONNECTOR_URL) + .getString(); + String connectorUser = connectorNode + .getProperty(AKB_CONNECTOR_USER).getString(); + String pwdPath = getPasswordPath(connectorNode); + char[] pwd = keyring.getAsChars(pwdPath); + + URI url = new URI(connectorUrl); + String host = url.getHost(); + int port = url.getPort(); + if (port == -1) + port = 22; + JSch jsch = new JSch(); + com.jcraft.jsch.Session sess = jsch.getSession(connectorUser, host, + port); + SimpleUserInfo userInfo = new SimpleUserInfo(); + userInfo.setPassword(new String(pwd)); + sess.setUserInfo(userInfo); + sess.connect(); + + sess.openChannel("exec"); + final ChannelExec channel = (ChannelExec) sess.openChannel("exec"); + channel.setCommand(command); + + channel.setInputStream(null); + channel.setXForwarding(false); + channel.setAgentForwarding(false); + channel.setErrStream(null); + + channel.connect(); + + String output = IOUtils.toString(channel.getInputStream()); + channel.disconnect(); + + sess.disconnect(); + + return output; + } catch (Exception e) { + throw new SlcException("Cannot execute command", e); + } + + } + + protected String getPasswordPath(Node node) throws RepositoryException { + Node home = UserJcrUtils.getUserHome(node.getSession()); + if (node.getPath().startsWith(home.getPath())) + return node.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD; + else + return home.getPath() + node.getPath() + '/' + + ArgeoNames.ARGEO_PASSWORD; + } + + private void savePassword(Session session, String pwdPath, char[] pwd) + throws RepositoryException { + if (!session.itemExists(pwdPath)) { + JcrUtils.mkdirs(session, JcrUtils.parentPath(pwdPath)); + session.save(); + keyring.set(pwdPath, pwd); + } + + } + + // /** Expose injected repository */ + // public Repository getRepository() { + // return repository; + // } + /* DEPENDENCY INJECTION */ public void setRepository(Repository repository) { this.repository = repository; @@ -76,4 +346,9 @@ public class AkbServiceImpl implements AkbNames { public void setDemoData(Map demoData) { this.demoData = demoData; } + + public void setKeyring(Keyring keyring) { + this.keyring = keyring; + } + } \ No newline at end of file