]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java
JDBC, SSH command (+ pseudo file retrieval) and keyring
[gpl/argeo-slc.git] / runtime / org.argeo.slc.akb / src / main / java / org / argeo / slc / akb / core / AkbServiceImpl.java
index b228b0a75a073f6db754c2dd93fe221d66054603..ba7b6cc0470273a88bd118ce77588c8320f87d6f 100644 (file)
@@ -1,5 +1,11 @@
 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;
@@ -8,15 +14,23 @@ import javax.jcr.Property;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
 
+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
@@ -28,6 +42,8 @@ public class AkbServiceImpl implements AkbService, AkbNames {
        /* DEPENDENCY INJECTION */
        private Repository repository;
 
+       private Keyring keyring;
+
        // Populate the repository in a demo context.
        private Map<String, Resource> demoData = null;
 
@@ -37,6 +53,10 @@ public class AkbServiceImpl implements AkbService, AkbNames {
         * receive/provide data.
         */
        public void init() {
+               // JDBC drivers
+               // TODO make it configurable
+               initJdbcDriver("org.postgresql.Driver");
+
                Session adminSession = null;
                try {
                        adminSession = repository.login();
@@ -63,6 +83,18 @@ public class AkbServiceImpl implements AkbService, AkbNames {
                }
        }
 
+       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() {
        }
@@ -76,19 +108,231 @@ public class AkbServiceImpl implements AkbService, AkbNames {
                Node newTemplate = parentNode.addNode(name, AkbTypes.AKB_ENV_TEMPLATE);
                newTemplate.setProperty(Property.JCR_TITLE, name);
 
-               Node connectorParent = newTemplate.addNode(connectorParentName,
-                               NodeType.NT_UNSTRUCTURED);
-               connectorParent.addMixin(NodeType.MIX_TITLE);
+               Node connectorParent = newTemplate.addNode(
+                               AkbTypes.AKB_CONNECTOR_FOLDER, AkbTypes.AKB_CONNECTOR_FOLDER);
                connectorParent.setProperty(Property.JCR_TITLE, connectorParentName);
 
-               Node itemsParent = newTemplate.addNode(itemsParentName,
-                               NodeType.NT_UNSTRUCTURED);
-               itemsParent.addMixin(NodeType.MIX_TITLE);
+               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;
@@ -102,4 +346,9 @@ public class AkbServiceImpl implements AkbService, AkbNames {
        public void setDemoData(Map<String, Resource> demoData) {
                this.demoData = demoData;
        }
+
+       public void setKeyring(Keyring keyring) {
+               this.keyring = keyring;
+       }
+
 }
\ No newline at end of file