]> git.argeo.org Git - gpl/argeo-slc.git/commitdiff
JDBC, SSH command (+ pseudo file retrieval) and keyring
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Nov 2013 19:17:35 +0000 (19:17 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Nov 2013 19:17:35 +0000 (19:17 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@6610 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

14 files changed:
modules/org.argeo.slc.akb.services/META-INF/spring/services-osgi.xml
modules/org.argeo.slc.akb.services/META-INF/spring/services.xml
modules/org.argeo.slc.akb.services/pom.xml
plugins/org.argeo.slc.akb.ui/META-INF/spring/editors.xml
plugins/org.argeo.slc.akb.ui/pom.xml
plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/ConnectorAliasEditor.java
plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/JdbcQueryTemplateEditor.java
plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/JdbcTestPage.java [new file with mode: 0644]
plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/SshCommandTemplateEditor.java
plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/SshFileTemplateEditor.java
runtime/org.argeo.slc.akb/pom.xml
runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbNames.java
runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbService.java
runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/core/AkbServiceImpl.java

index 9b792f372433fcd182a59a879c392e3b754adf91..cbc38157a8a612355e75f6bc8a1b5d74aa1f861e 100644 (file)
@@ -23,4 +23,7 @@
                </service-properties>\r
        </service>\r
        <service ref="akbService" interface="org.argeo.slc.akb.AkbService" />\r
+\r
+       <reference id="keyring" interface="org.argeo.security.crypto.CryptoKeyring" />\r
+\r
 </beans:beans>
index fc42e138649822fcc9f7dd17afb9839ed618af0f..0711d655568a18b8b76997293f1122d53104c955 100644 (file)
@@ -8,6 +8,7 @@
        <bean id="akbService" class="org.argeo.slc.akb.core.AkbServiceImpl"\r
                init-method="init" destroy-method="destroy">\r
                <property name="repository" ref="akbRepository" />\r
+               <property name="keyring" ref="keyring" />\r
        </bean>\r
        <bean\r
                class="org.argeo.security.core.AuthenticatedApplicationContextInitialization">\r
index 5b3c4f919279a75c6d7ae5e84036c9669c899cc2..0618a7119511d6211ac12ce376ded8e0c203cf8e 100644 (file)
@@ -19,7 +19,7 @@
                                        <instructions>
                                                <Import-Package>
                                                        *,
-                                                       org.argeo.slc.akb
+                                                       org.argeo.slc.akb,
                                                 </Import-Package>
                                        </instructions>
                                </configuration>
index 52d1340188a650f1ca8a4540751640775702bbc1..730a9c6617a7dd586cef267a4c46392007ab97cb 100644 (file)
        <bean id="jdbcQueryTemplateEditor" class="org.argeo.slc.akb.ui.editors.JdbcQueryTemplateEditor"
                scope="prototype">
                <property name="repository" ref="repository" />
+               <property name="akbService" ref="akbService" />
        </bean>
        <bean id="sshCommandTemplateEditor" class="org.argeo.slc.akb.ui.editors.SshCommandTemplateEditor"
                scope="prototype">
                <property name="repository" ref="repository" />
+               <property name="akbService" ref="akbService" />
        </bean>
        <bean id="sshFileTemplateEditor" class="org.argeo.slc.akb.ui.editors.SshFileTemplateEditor"
                scope="prototype">
                <property name="repository" ref="repository" />
+               <property name="akbService" ref="akbService" />
        </bean>
 </beans>
\ No newline at end of file
index e5f2c2d1755ceb44a1b190335b51cbce7a9b2f17..c40bca7b1977b232437472d6a1c0ab1e36162b0c 100644 (file)
                        <artifactId>org.argeo.eclipse.ui</artifactId>
                        <version>${version.argeo-commons}</version>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.security</groupId>
+                       <artifactId>org.argeo.security.ui</artifactId>
+                       <version>${version.argeo-commons}</version>
+               </dependency>
 
                <!-- RAP only dependency, needed at compile time -->
                <dependency>
index b272a38f4763dac331a799ecd7739d7a56b5601b..a69fdcf3a5078cec7abaa22d7db374f331cc4024 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.slc.akb.ui.editors;
 import javax.jcr.Property;
 import javax.jcr.RepositoryException;
 
+import org.argeo.eclipse.ui.ErrorFeedback;
 import org.argeo.slc.akb.AkbException;
 import org.argeo.slc.akb.AkbNames;
 import org.argeo.slc.akb.AkbTypes;
@@ -106,7 +107,7 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor {
                        public void modifyText(ModifyEvent event) {
 
                                try { // TODO enhance this
-                                       // retrieve old and new node type
+                                               // retrieve old and new node type
                                        int oldIndex = getCurrTypeIndex();
                                        int selIndex = typeCmb.getSelectionIndex();
 
@@ -158,12 +159,16 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor {
 
                Composite firstLine = getToolkit().createComposite(group);
                firstLine.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               firstLine.setLayout(new GridLayout(3, false));
+               firstLine.setLayout(new GridLayout(2, false));
 
                getToolkit().createLabel(firstLine, "URL");
                final Text urlTxt = getToolkit().createText(firstLine, "", SWT.BORDER);
                urlTxt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
 
+               getToolkit().createLabel(firstLine, "User");
+               final Text userTxt = getToolkit().createText(firstLine, "", SWT.BORDER);
+               userTxt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
                final Button testBtn = getToolkit().createButton(firstLine,
                                "Test connection", SWT.PUSH);
                // testBtn.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false,
@@ -176,17 +181,27 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor {
                                // update display value
                                AkbUiUtils.refreshFormTextWidget(urlTxt, getAkbNode(),
                                                AkbNames.AKB_CONNECTOR_URL);
+                               AkbUiUtils.refreshFormTextWidget(userTxt, getAkbNode(),
+                                               AkbNames.AKB_CONNECTOR_USER);
                        }
                };
                // Listeners
                AkbUiUtils.addTextModifyListener(urlTxt, getAkbNode(),
                                AkbNames.AKB_CONNECTOR_URL, part);
+               AkbUiUtils.addTextModifyListener(userTxt, getAkbNode(),
+                               AkbNames.AKB_CONNECTOR_USER, part);
 
                testBtn.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
-                               boolean testSuccesfull = getAkbService().testConnector(
-                                               getAkbNode());
+                               boolean testSuccesfull;
+                               try {
+                                       testSuccesfull = getAkbService()
+                                                       .testConnector(getAkbNode());
+                               } catch (Exception e1) {
+                                       testSuccesfull = false;
+                                       ErrorFeedback.show("Cannot test connection", e1);
+                               }
 
                                String name = AkbJcrUtils.get(getAkbNode(), Property.JCR_TITLE);
                                String url = AkbJcrUtils.get(getAkbNode(),
index aea5f0aea1a665b604ca5d110a5092532dea7236..078db17baed85d3866876084e6d85825a4a24f6e 100644 (file)
@@ -9,6 +9,7 @@ import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.forms.AbstractFormPart;
 import org.eclipse.ui.forms.IManagedForm;
 
@@ -58,4 +59,10 @@ public class JdbcQueryTemplateEditor extends AkbItemTemplateEditor {
                managedForm.addPart(part);
        }
 
+       @Override
+       protected void addOtherPages() throws PartInitException {
+               addPage(new JdbcTestPage(getAkbService(), this, "testPage", "Test",
+                               getAkbNode()));
+       }
+
 }
diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/JdbcTestPage.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/JdbcTestPage.java
new file mode 100644 (file)
index 0000000..7189f5f
--- /dev/null
@@ -0,0 +1,215 @@
+package org.argeo.slc.akb.ui.editors;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.security.ui.PrivilegedJob;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.akb.AkbNames;
+import org.argeo.slc.akb.AkbService;
+import org.argeo.slc.akb.ui.AkbUiUtils;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+/** Test JDBC. */
+public class JdbcTestPage extends FormPage implements AkbNames {
+       private Node node;
+       private AkbService akbService;
+
+       private TableViewer viewer = null;
+       private IContentProvider contentProvider;
+
+       private PreparedStatement statement;
+
+       public JdbcTestPage(AkbService akbService, FormEditor editor, String id,
+                       String title, Node node) {
+               super(editor, id, title);
+               this.akbService = akbService;
+               this.node = node;
+       }
+
+       protected void createFormContent(IManagedForm managedForm) {
+               super.createFormContent(managedForm);
+               ScrolledForm form = managedForm.getForm();
+               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               Composite parent = form.getBody();
+
+               parent.setLayout(AkbUiUtils.gridLayoutNoBorder());
+               FormToolkit toolkit = getEditor().getToolkit();
+               Table table = toolkit.createTable(parent, SWT.VIRTUAL);
+               table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               table.setHeaderVisible(true);
+               table.setLinesVisible(true);
+               viewer = new TableViewer(table);
+               contentProvider = new JdbcTestContentProvider(viewer);
+               viewer.setContentProvider(contentProvider);
+               // viewer.setLabelProvider(new ColumnLabelProvider(){});
+
+               statement = akbService.prepareJdbcQuery(node);
+               PrivilegedJob job = new PrivilegedJob("Execute query on " + node) {
+
+                       @Override
+                       protected IStatus doRun(IProgressMonitor progressMonitor) {
+                               try {
+                                       final ResultSet resultSet = statement.executeQuery();
+                                       getEditorSite().getWorkbenchWindow().getShell()
+                                                       .getDisplay().syncExec(new Runnable() {
+
+                                                               @Override
+                                                               public void run() {
+                                                                       viewer.setInput(resultSet);
+                                                               }
+                                                       });
+                                       return Status.OK_STATUS;
+                               } catch (SQLException e) {
+                                       throw new SlcException("Cannot execute " + node, e);
+                               }
+                       }
+               };
+               job.schedule();
+       }
+
+       @Override
+       public void dispose() {
+               try {
+                       statement.close();
+                       statement.getConnection().close();
+               } catch (SQLException e) {
+                       // silent
+               }
+       }
+
+       private class JdbcTestContentProvider implements ILazyContentProvider {
+               private TableViewer viewer;
+               private ResultSet resultSet;
+               private boolean isScrollable;
+
+               private List<Object> buffer = new ArrayList<Object>();
+
+               private List<JdbcColumn> columns = new ArrayList<JdbcColumn>();
+               private Integer columnCount = 0;
+
+               private int rowCount = 0;
+
+               public JdbcTestContentProvider(TableViewer viewer) {
+                       this.viewer = viewer;
+               }
+
+               public void dispose() {
+                       try {
+                               resultSet.close();
+                       } catch (SQLException e) {
+                               // silent
+                       }
+               }
+
+               public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+                       if (newInput == null)
+                               return;
+
+                       TableViewer viewer = (TableViewer) v;
+
+                       resultSet = (ResultSet) newInput;
+                       try {
+                               isScrollable = resultSet.getType() != ResultSet.TYPE_FORWARD_ONLY;
+                               columnCount = resultSet.getMetaData().getColumnCount();
+                               for (int i = 1; i <= columnCount; i++) {
+                                       columns.add(new JdbcColumn(i, resultSet.getMetaData()));
+                                       if (oldInput == null)// first time
+                                               addColumn(viewer, i - 1);
+                               }
+
+                               if (isScrollable) {
+                                       if (resultSet.next())
+                                               rowCount = 1;
+                                       viewer.setItemCount(rowCount);
+                               } else {
+                                       while (resultSet.next()) {
+                                               Object[] lst = new Object[columnCount];
+                                               for (int i = 1; i <= columnCount; i++) {
+                                                       lst[i - 1] = resultSet.getObject(i);
+                                                       buffer.add(lst);
+                                               }
+                                       }
+                                       viewer.setItemCount(buffer.size());
+                               }
+
+                       } catch (SQLException e) {
+                               throw new SlcException("Cannot configure JDBC column", e);
+                       }
+               }
+
+               protected void addColumn(TableViewer viewer, final int index) {
+                       TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
+                       col.getColumn().setWidth(100);
+                       col.getColumn().setText(columns.get(index).name);
+                       col.setLabelProvider(new ColumnLabelProvider() {
+                               @Override
+                               public String getText(Object element) {
+                                       return ((Object[]) element)[index].toString();
+                               }
+                       });
+               }
+
+               public void updateElement(int index) {
+                       if (resultSet == null)
+                               return;
+
+                       try {
+                               if (isScrollable) {
+                                       resultSet.absolute(index + 1);
+                                       Object[] lst = new Object[columnCount];
+                                       for (int i = 1; i <= columnCount; i++) {
+                                               lst[i - 1] = resultSet.getObject(i);
+                                       }
+                                       viewer.replace(lst, index);
+                                       int itemCount = viewer.getTable().getItemCount();
+                                       if (index == (itemCount - 1) && resultSet.next())
+                                               viewer.setItemCount(itemCount + 1);
+                               } else {
+                                       viewer.replace(buffer.get(index), index);
+                               }
+                       } catch (Exception e) {
+                               throw new SlcException("Cannot update element", e);
+                       }
+               }
+       }
+
+       private class JdbcColumn {
+               // public final Integer index;
+               public final String name;
+
+               // public final Integer type;
+
+               public JdbcColumn(int index, ResultSetMetaData metaData)
+                               throws SQLException {
+                       // this.index = index;
+                       this.name = metaData.getColumnName(index);
+                       // this.type = metaData.getColumnType(index);
+
+               }
+       }
+
+}
index 7c730502c3895aca63f68102e5baac27301c7bc3..a91420c4389f8d6229b8f400ec062ab72b329224 100644 (file)
@@ -4,6 +4,7 @@ import org.argeo.slc.akb.AkbNames;
 import org.argeo.slc.akb.ui.AkbUiPlugin;
 import org.argeo.slc.akb.ui.AkbUiUtils;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
@@ -25,13 +26,28 @@ public class SshCommandTemplateEditor extends AkbItemTemplateEditor {
                return ID;
        }
 
+       @Override
+       protected void populateTestPage(Composite parent) {
+               parent.setLayout(AkbUiUtils.gridLayoutNoBorder());
+
+               Text outputDisplay = getToolkit().createText(parent, "", SWT.MULTI);
+               outputDisplay.setFont(new Font(parent.getDisplay(), "Monospaced", 10,
+                               SWT.NONE));
+               outputDisplay.setEditable(false);
+               outputDisplay
+                               .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+               String output = getAkbService().executeCommand(getAkbNode());
+               outputDisplay.setText(output);
+       }
+
        @Override
        protected void populateBottomPart(Composite parent, IManagedForm managedForm) {
                parent.setLayout(AkbUiUtils.gridLayoutNoBorder());
                Group group = new Group(parent, SWT.NO_FOCUS);
                getToolkit().adapt(group, false, false);
                group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               
+
                group.setLayout(new GridLayout(1, false));
 
                // first line: Description
index d4712bcc894d36ba21829a00226c7466fc802a64..309bedeba64a2699f8c666202607e27c3f24f7be 100644 (file)
@@ -4,6 +4,7 @@ import org.argeo.slc.akb.AkbNames;
 import org.argeo.slc.akb.ui.AkbUiPlugin;
 import org.argeo.slc.akb.ui.AkbUiUtils;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
@@ -25,6 +26,21 @@ public class SshFileTemplateEditor extends AkbItemTemplateEditor {
                return ID;
        }
 
+       @Override
+       protected void populateTestPage(Composite parent) {
+               parent.setLayout(AkbUiUtils.gridLayoutNoBorder());
+
+               Text outputDisplay = getToolkit().createText(parent, "", SWT.MULTI);
+               outputDisplay.setFont(new Font(parent.getDisplay(), "Monospaced", 10,
+                               SWT.NONE));
+               outputDisplay.setEditable(false);
+               outputDisplay
+                               .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+               String output = getAkbService().retrieveFile(getAkbNode());
+               outputDisplay.setText(output);
+       }
+
        @Override
        protected void populateBottomPart(Composite parent, IManagedForm managedForm) {
                parent.setLayout(AkbUiUtils.gridLayoutNoBorder());
index 66f50271573dd0d5d3fa19d77f89bb1f733f5c68..f6e27e7e569b435c61968706dc93d5f41c2b466d 100644 (file)
                                                <Import-Package>
                                                        *,
                                                        javax.jcr.nodetype,
+                                                       com.microsoft.sqlserver.jdbc;resolution:=optional,
+                                                       com.mysql.jdbc;resolution:=optional,
+                                                       net.sourceforge.jtds.jdbc;resolution:=optional,
+                                                       oracle.jdbc;resolution:=optional,
+                                                       org.apache.derby.jdbc;resolution:=optional,
+                                                       org.h2;resolution:=optional,
+                                                       org.hsqldb;resolution:=optional,
+                                                       org.postgresql;resolution:=optional
                                                </Import-Package>
                                        </instructions>
                                </configuration>
                        <artifactId>org.argeo.security.core</artifactId>
                        <version>${version.argeo-commons}</version>
                </dependency>
+
+               <!-- SLC -->
+               <dependency>
+                       <groupId>org.argeo.slc</groupId>
+                       <artifactId>org.argeo.slc.support.simple</artifactId>
+                       <version>1.1.15-SNAPSHOT</version>
+               </dependency>
        </dependencies>
 </project>
index 018f094a3376e240cee7762b34621d59305a4d83..76248a842f6f0d2293bcc570691f19bd4aec0854 100644 (file)
@@ -17,6 +17,7 @@ public interface AkbNames {
 
        /* CONNECTOR PROPERTIES */
        public final static String AKB_CONNECTOR_URL = "akb:connectorUrl";
+       public final static String AKB_CONNECTOR_USER = "akb:connectorUser";
 
        /* ITEMS PROPERTIES */
        public final static String AKB_USED_CONNECTOR = "akb:usedConnector";
index 1f39ff832bec4c412a7a7a26780ad89d16c4ce5c..8a16c63d3b0ecab8911cf85db61a388b051720d5 100644 (file)
@@ -1,5 +1,7 @@
 package org.argeo.slc.akb;
 
+import java.sql.PreparedStatement;
+
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
@@ -16,4 +18,10 @@ public interface AkbService {
         * current user has the sufficient credentials to connect
         */
        public boolean testConnector(Node connector);
+
+       public PreparedStatement prepareJdbcQuery(Node node);
+
+       public String executeCommand(Node node);
+
+       public String retrieveFile(Node node);
 }
index e819bbfa82a858803de4e44e89b7bce31aa4cf36..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;
@@ -9,13 +15,22 @@ 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
@@ -27,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;
 
@@ -36,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();
@@ -62,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() {
        }
@@ -89,9 +122,215 @@ public class AkbServiceImpl implements AkbService, AkbNames {
        // ///////////////////////////////////////
        // / CONNECTORS
 
-       public boolean testConnector(Node connector) {
-               // TODO Implement this.
-               return false;
+       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 */
@@ -107,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