From: Bruno Sinou Date: Thu, 14 Nov 2013 15:19:02 +0000 (+0000) Subject: Some work in progress on AKB UI. Does not work. Must be yet committed to easily switc... X-Git-Tag: argeo-slc-2.1.7~285 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=65c1e73020652f7b70110268de6cc2c89624a9c2;p=gpl%2Fargeo-slc.git Some work in progress on AKB UI. Does not work. Must be yet committed to easily switch computers... git-svn-id: https://svn.argeo.org/slc/trunk@6613 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/plugins/org.argeo.slc.akb.ui/META-INF/spring/editors.xml b/plugins/org.argeo.slc.akb.ui/META-INF/spring/editors.xml index 730a9c661..55c706d0a 100644 --- a/plugins/org.argeo.slc.akb.ui/META-INF/spring/editors.xml +++ b/plugins/org.argeo.slc.akb.ui/META-INF/spring/editors.xml @@ -6,6 +6,7 @@ + + + + + @@ -99,9 +107,45 @@ name="The Node JCR ID if needed"> + + + + + + + + + + + + + + + + diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbImages.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbImages.java index 32241afd8..600760446 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbImages.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbImages.java @@ -1,5 +1,6 @@ package org.argeo.slc.akb.ui; +import org.argeo.slc.akb.AkbTypes; import org.eclipse.swt.graphics.Image; /** Shared icons. */ @@ -26,4 +27,13 @@ public class AkbImages { "icons/sshCommand.png").createImage(); public final static Image SSH_FILE = AkbUiPlugin.getImageDescriptor( "icons/sshFile.gif").createImage(); + + public static Image getImageForAkbNodeType(String nodeType) { + if (AkbTypes.AKB_JDBC_CONNECTOR.equals(nodeType)) + return JDBC_CONNECTOR; + else if (AkbTypes.AKB_SSH_CONNECTOR.equals(nodeType)) + return SSH_CONNECTOR; + else + return null; + } } diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbMessages.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbMessages.java new file mode 100644 index 000000000..521150378 --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbMessages.java @@ -0,0 +1,37 @@ +package org.argeo.slc.akb.ui; + +import java.util.HashMap; +import java.util.Map; + +import org.argeo.slc.akb.AkbTypes; + +// TODO implement i18n +public class AkbMessages { + + // Shortcut to provide a label for each nodeType + public final static Map typeLabels = new HashMap() { + private static final long serialVersionUID = 6790463815849374432L; + + { + put(AkbTypes.AKB_ENV_TEMPLATE, "Template environment"); + put(AkbTypes.AKB_ENV, "Active environment"); + put(AkbTypes.AKB_CONNECTOR_FOLDER, "Connector folder"); + put(AkbTypes.AKB_CONNECTOR, "Connector"); + put(AkbTypes.AKB_CONNECTOR_ALIAS, "Connector alias"); + put(AkbTypes.AKB_SSH_CONNECTOR, "SSH connector"); + put(AkbTypes.AKB_JDBC_CONNECTOR, "JDBC connector"); + put(AkbTypes.AKB_JCR_CONNECTOR, "JCR connector"); + put(AkbTypes.AKB_ITEM_FOLDER, "Item folder"); + put(AkbTypes.AKB_ITEM, "Item"); + put(AkbTypes.AKB_SSH_FILE, "SSH file"); + put(AkbTypes.AKB_SSH_COMMAND, "SSH command"); + put(AkbTypes.AKB_JDBC_QUERY, "JDBC query"); + put(AkbTypes.AKB_NOTE, "Note"); + } + }; + + public final static String getLabelForType(String nodeType) { + return typeLabels.get(nodeType); + } + +} diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbUiUtils.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbUiUtils.java index 38ddcbffe..8012a8b08 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbUiUtils.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbUiUtils.java @@ -1,6 +1,7 @@ package org.argeo.slc.akb.ui; import java.util.Calendar; +import java.util.Map; import javax.jcr.Node; import javax.jcr.PropertyType; @@ -8,6 +9,9 @@ import javax.jcr.RepositoryException; import org.argeo.slc.akb.AkbException; import org.argeo.slc.akb.utils.AkbJcrUtils; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; @@ -23,6 +27,9 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.menus.CommandContributionItem; +import org.eclipse.ui.menus.CommandContributionItemParameter; +import org.eclipse.ui.services.IServiceLocator; /** Some helper methods that factorize widely used snippets in people UI */ public class AkbUiUtils { @@ -51,16 +58,17 @@ public class AkbUiUtils { text.setEnabled(AkbJcrUtils.isNodeCheckedOutByMe(entity)); return tmpStr; } - - + /** * Shortcut to refresh a Text widget given a Node in a form and - * a property Name. Also manages its enable state and set a default message if corresponding Text value is empty + * a property Name. Also manages its enable state and set a default message + * if corresponding Text value is empty */ public static String refreshFormTextWidget(Text text, Node entity, String propName, String defaultMsg) { String tmpStr = refreshFormTextWidget(text, entity, propName); - if (AkbJcrUtils.isEmptyString(tmpStr) && AkbJcrUtils.checkNotEmptyString(defaultMsg)) + if (AkbJcrUtils.isEmptyString(tmpStr) + && AkbJcrUtils.checkNotEmptyString(defaultMsg)) text.setMessage(defaultMsg); return tmpStr; } @@ -267,4 +275,48 @@ public class AkbUiUtils { formData.bottom = new FormAttachment(bottom, 0); return formData; } + + // ////////////////////////////// + // / COMMANDS + public static CommandContributionItem createContributionItem( + IMenuManager menuManager, IServiceLocator locator, String itemId, + String cmdId, String label, ImageDescriptor icon, + Map params) { + + CommandContributionItemParameter contributionItemParameter = new CommandContributionItemParameter( + locator, itemId, cmdId, SWT.PUSH); + + contributionItemParameter.label = label; + contributionItemParameter.icon = icon; + + if (params != null) + contributionItemParameter.parameters = params; + CommandContributionItem cci = new CommandContributionItem( + contributionItemParameter); + return cci; + } + + /** + * Commodities the refresh of a single command with a map of parameters in a + * Menu.aboutToShow method to simplify further development + * + * @param menuManager + * @param locator + * @param cmdId + * @param label + * @param iconPath + * @param showCommand + */ + public static void refreshParameterizedCommand(IMenuManager menuManager, + IServiceLocator locator, String itemId, String cmdId, String label, + ImageDescriptor icon, boolean showCommand, + Map params) { + IContributionItem ici = menuManager.find(itemId); + if (ici != null) + menuManager.remove(ici); + if (showCommand) + menuManager.add(createContributionItem(menuManager, locator, + itemId, cmdId, label, icon, params)); + } + } \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java index 9889ae00e..2faafa38b 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java @@ -9,6 +9,7 @@ import org.argeo.jcr.JcrUtils; import org.argeo.slc.akb.AkbException; import org.argeo.slc.akb.ui.AkbUiPlugin; import org.argeo.slc.akb.ui.editors.AkbNodeEditorInput; +import org.argeo.slc.akb.utils.AkbJcrUtils; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; @@ -47,8 +48,12 @@ public class DeleteAkbNodes extends AbstractHandler { if (nodeJcrId != null) node = session.getNodeByIdentifier(nodeJcrId); + // We must be in a template to delete nodes... + Node template = AkbJcrUtils.getCurrentTemplate(node); + IEditorPart currPart = currentPage - .findEditor(new AkbNodeEditorInput(nodeJcrId)); + .findEditor(new AkbNodeEditorInput( + template.getIdentifier(), nodeJcrId)); if (currPart != null) currPart.dispose(); diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/ForceRefresh.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/ForceRefresh.java new file mode 100644 index 000000000..0344b7beb --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/ForceRefresh.java @@ -0,0 +1,27 @@ +package org.argeo.slc.akb.ui.commands; + +import org.argeo.slc.akb.ui.AkbUiPlugin; +import org.argeo.slc.akb.ui.utils.Refreshable; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Force refreshment of the active part if it implements + * Refreshable interface. + */ +public class ForceRefresh extends AbstractHandler { + + public final static String ID = AkbUiPlugin.PLUGIN_ID + ".forceRefresh"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + IWorkbenchPart part = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getActivePart(); + if (part instanceof Refreshable) + ((Refreshable) part).forceRefresh(null); + return null; + } +} \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenAkbNodeEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenAkbNodeEditor.java index 527033e19..a04bde084 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenAkbNodeEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenAkbNodeEditor.java @@ -11,6 +11,7 @@ import org.argeo.jcr.JcrUtils; import org.argeo.slc.akb.AkbException; import org.argeo.slc.akb.AkbService; import org.argeo.slc.akb.AkbTypes; +import org.argeo.slc.akb.ui.AkbMessages; import org.argeo.slc.akb.ui.AkbUiPlugin; import org.argeo.slc.akb.ui.dialogs.AddItemDialog; import org.argeo.slc.akb.ui.editors.AkbNodeEditorInput; @@ -48,11 +49,15 @@ public class OpenAkbNodeEditor extends AbstractHandler { public final static String PARAM_NODE_JCR_ID = "param.nodeJcrId"; public final static String PARAM_NODE_TYPE = "param.nodeType"; + public final static String PARAM_NODE_SUBTYPE = "param.nodeSubtype"; + public final static String PARAM_CURR_ENV_JCR_ID = "param.currEnvJcrId"; public final static String PARAM_PARENT_NODE_JCR_ID = "param.parentNodeJcrId"; public Object execute(ExecutionEvent event) throws ExecutionException { String nodeType = event.getParameter(PARAM_NODE_TYPE); + String nodeSubtype = event.getParameter(PARAM_NODE_SUBTYPE); + String currEnvJcrId = event.getParameter(PARAM_CURR_ENV_JCR_ID); String nodeJcrId = event.getParameter(PARAM_NODE_JCR_ID); String parentNodeJcrId = event.getParameter(PARAM_PARENT_NODE_JCR_ID); @@ -70,7 +75,8 @@ public class OpenAkbNodeEditor extends AbstractHandler { throw new AkbException( "Define a parent node to create a new node"); else - node = createNewNode(session, nodeType, parentNodeJcrId); + node = createNewNode(session, nodeType, nodeSubtype, + parentNodeJcrId); else node = session.getNodeByIdentifier(nodeJcrId); @@ -84,7 +90,7 @@ public class OpenAkbNodeEditor extends AbstractHandler { if (editorId == null) return null; - AkbNodeEditorInput eei = new AkbNodeEditorInput( + AkbNodeEditorInput eei = new AkbNodeEditorInput(currEnvJcrId, node.getIdentifier()); currentPage.openEditor(eei, editorId); @@ -102,7 +108,8 @@ public class OpenAkbNodeEditor extends AbstractHandler { } private Node createNewNode(Session session, String nodeType, - String parentNodeJcrId) throws RepositoryException { + String nodeSubtype, String parentNodeJcrId) + throws RepositoryException { Node node = null; if (AkbTypes.AKB_ITEM.equals(nodeType)) { @@ -112,12 +119,25 @@ public class OpenAkbNodeEditor extends AbstractHandler { dialog.open(); node = dialog.getNewNode(); } else { - String name = SingleValue.ask("New name", "Create AKB item"); + String name = SingleValue + .ask("Create " + + AkbMessages + .getLabelForType(nodeSubtype == null ? nodeType + : nodeSubtype), + "Please enter a name for the corresponding " + + AkbMessages + .getLabelForType(nodeSubtype == null ? nodeType + : nodeSubtype)); if (name == null) return null; if (AkbTypes.AKB_ENV_TEMPLATE.equals(nodeType)) { node = akbService.createAkbTemplate( session.getNodeByIdentifier(parentNodeJcrId), name); + } else if (AkbTypes.AKB_CONNECTOR_ALIAS.equals(nodeType)) { + // the Jcr ID of the corresponding template must be passed to + // create a new alias + node = session.getNodeByIdentifier(parentNodeJcrId); + akbService.createConnectorAlias(node, name, nodeSubtype); } else { Node parentNode = session.getNodeByIdentifier(parentNodeJcrId); node = parentNode.addNode(name, nodeType); diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenTracker.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenTracker.java new file mode 100644 index 000000000..a8d0e6850 --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/OpenTracker.java @@ -0,0 +1,31 @@ +package org.argeo.slc.akb.ui.commands; + +import java.net.URL; + +import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.ui.AkbUiPlugin; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.PlatformUI; + +/** + * Open a browser with bugzilla + */ +public class OpenTracker extends AbstractHandler { + + public final static String ID = AkbUiPlugin.PLUGIN_ID + ".forceRefresh"; + + private final static String TRACKER_URL = "https://www.argeo.org/bugzilla/enter_bug.cgi?product=slc"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + try { + PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser() + .openURL(new URL(TRACKER_URL)); + } catch (Exception e) { + throw new AkbException("Unable to open browser page", e); + } + return null; + } +} \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ConnectorAliasSmallComposite.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ConnectorAliasSmallComposite.java new file mode 100644 index 000000000..3c0726fac --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ConnectorAliasSmallComposite.java @@ -0,0 +1,201 @@ +package org.argeo.slc.akb.ui.composites; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.utils.CommandUtils; +import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.AkbNames; +import org.argeo.slc.akb.AkbService; +import org.argeo.slc.akb.ui.AkbImages; +import org.argeo.slc.akb.ui.AkbUiUtils; +import org.argeo.slc.akb.ui.commands.DeleteAkbNodes; +import org.argeo.slc.akb.utils.AkbJcrUtils; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.widgets.FormToolkit; + +/** Default composite to display a connector alias. */ +public class ConnectorAliasSmallComposite extends Composite { + + private final AkbService akbService; + private final Node connectorAlias; + private final Node activeConnector; + private final FormToolkit toolkit; + private final IManagedForm form; + + // Don't forget to unregister on dispose + private AbstractFormPart formPart; + + // To enable set focus + private Text titleTxt; + + public ConnectorAliasSmallComposite(Composite parent, int style, + FormToolkit toolkit, IManagedForm form, Node akbNode, + AkbService akbService) { + super(parent, style); + this.connectorAlias = akbNode; + try { + this.activeConnector = akbNode + .getNode(AkbNames.AKB_DEFAULT_TEST_CONNECTOR); + } catch (RepositoryException e) { + throw new AkbException("Unable to get activeConnector for node", e); + } + this.toolkit = toolkit; + this.form = form; + this.akbService = akbService; + populate(); + toolkit.adapt(this); + } + + private void populate() { + // Initialization + Composite parent = this; + createConnectorAliasInfoCmp(parent); + } + + private void createConnectorAliasInfoCmp(Composite parent) { + GridLayout gl = AkbUiUtils.gridLayoutNoBorder(); + gl.marginBottom = 15; + + parent.setLayout(gl); + Composite firstLine = toolkit.createComposite(parent, SWT.NO_FOCUS); + firstLine.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + firstLine.setLayout(new GridLayout(9, false)); + + // Image + final Label image = toolkit.createLabel(firstLine, "", SWT.NONE); + GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false); + try { + image.setImage(AkbImages.getImageForAkbNodeType(activeConnector + .getPrimaryNodeType().getName())); + } catch (RepositoryException e2) { + // silent + } + image.setLayoutData(gd); + + // Name + final Text titleTxt = toolkit.createText(firstLine, "", SWT.BORDER); + gd = new GridData(SWT.FILL, SWT.TOP, false, false); + gd.widthHint = 150; + titleTxt.setLayoutData(gd); + + toolkit.createLabel(firstLine, "URL"); + final Text urlTxt = toolkit.createText(firstLine, "", SWT.BORDER); + urlTxt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + toolkit.createLabel(firstLine, "User"); + final Text userTxt = toolkit.createText(firstLine, "", SWT.BORDER); + gd = new GridData(SWT.LEFT, SWT.TOP, false, false); + gd.widthHint = 150; + userTxt.setLayoutData(gd); + + final Link testBtn = new Link(firstLine, SWT.NONE); + toolkit.adapt(testBtn, false, false); + testBtn.setText("Test"); + + final Link removeBtn = new Link(firstLine, SWT.NONE); + toolkit.adapt(removeBtn, false, false); + removeBtn.setText("Delete"); + + // createDefaultTestConnectorCmp(secondLine); + + // Description + final Text descTxt = toolkit.createText(parent, "", SWT.NONE); + gd = new GridData(SWT.FILL, SWT.TOP, true, false); + descTxt.setLayoutData(gd); + + // Part Management + formPart = new AbstractFormPart() { + public void refresh() { + super.refresh(); + // update display value + AkbUiUtils.refreshFormTextWidget(titleTxt, connectorAlias, + Property.JCR_TITLE, "Name"); + AkbUiUtils.refreshFormTextWidget(descTxt, connectorAlias, + Property.JCR_DESCRIPTION, "Short description"); + AkbUiUtils.refreshFormTextWidget(urlTxt, activeConnector, + AkbNames.AKB_CONNECTOR_URL); + AkbUiUtils.refreshFormTextWidget(userTxt, activeConnector, + AkbNames.AKB_CONNECTOR_USER); + } + }; + // Listeners + AkbUiUtils.addTextModifyListener(titleTxt, connectorAlias, + Property.JCR_TITLE, formPart); + AkbUiUtils.addTextModifyListener(urlTxt, activeConnector, + AkbNames.AKB_CONNECTOR_URL, formPart); + AkbUiUtils.addTextModifyListener(userTxt, activeConnector, + AkbNames.AKB_CONNECTOR_USER, formPart); + AkbUiUtils.addTextModifyListener(descTxt, connectorAlias, + Property.JCR_DESCRIPTION, formPart); + + testBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean testSuccesfull; + try { + testSuccesfull = akbService.testConnector(activeConnector); + } catch (Exception e1) { + testSuccesfull = false; + ErrorFeedback.show("Cannot test connection", e1); + } + String name = AkbJcrUtils.get(activeConnector, + Property.JCR_TITLE); + String url = AkbJcrUtils.get(activeConnector, + AkbNames.AKB_CONNECTOR_URL); + String msg = " to " + name + " (" + url + ")"; + if (testSuccesfull) + MessageDialog.openInformation( + getDisplay().getActiveShell(), "Test successful", + "Successfully connected " + msg); + else + MessageDialog.openError(getDisplay().getActiveShell(), + "Test failure", "Unable to connect" + msg); + } + }); + + removeBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + CommandUtils.CallCommandWithOneParameter(DeleteAkbNodes.ID, + DeleteAkbNodes.PARAM_NODE_JCR_ID, + AkbJcrUtils.getIdentifierQuietly(connectorAlias)); + // for (IFormPart part : form.getParts()) + // if (!formPart.equals(part)) + // part.refresh(); + } + }); + form.addPart(formPart); + } + + @Override + public boolean setFocus() { + return titleTxt.setFocus(); + } + + protected void disposePart(AbstractFormPart part) { + if (part != null) { + form.removePart(part); + part.dispose(); + } + } + + @Override + public void dispose() { + disposePart(formPart); + super.dispose(); + } +} diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ItemTemplateTitleComposite.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ItemTemplateTitleComposite.java index 3b73d0939..ae2d235a3 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ItemTemplateTitleComposite.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/ItemTemplateTitleComposite.java @@ -8,8 +8,10 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import org.argeo.eclipse.ui.utils.CommandUtils; +import org.argeo.jcr.JcrUtils; import org.argeo.slc.akb.AkbException; import org.argeo.slc.akb.AkbNames; +import org.argeo.slc.akb.AkbService; import org.argeo.slc.akb.ui.AkbUiUtils; import org.argeo.slc.akb.ui.commands.OpenAkbNodeEditor; import org.argeo.slc.akb.utils.AkbJcrUtils; @@ -34,6 +36,7 @@ public class ItemTemplateTitleComposite extends Composite { // private final static Log log = // LogFactory.getLog(MixTitleComposite.class); + private final AkbService akbService; private final Node akbNode; private final FormToolkit toolkit; private final IManagedForm form; @@ -47,11 +50,13 @@ public class ItemTemplateTitleComposite extends Composite { private List definedAliases; public ItemTemplateTitleComposite(Composite parent, int style, - FormToolkit toolkit, IManagedForm form, Node akbNode) { + FormToolkit toolkit, IManagedForm form, Node akbNode, + AkbService akbService) { super(parent, style); this.akbNode = akbNode; this.toolkit = toolkit; this.form = form; + this.akbService = akbService; populate(); toolkit.adapt(this); } @@ -92,17 +97,6 @@ public class ItemTemplateTitleComposite extends Composite { "No selected alias"); } }); - // - // final Link testAliasLk= new Link(parent, SWT.NONE); - // openAliasLk.setText(" Edit Alias "); - // openAliasLk.addSelectionListener(new SelectionAdapter() { - // private static final long serialVersionUID = 1L; - // - // @Override - // public void widgetSelected(final SelectionEvent event) { - // MessageDialog.openInformation(getShell(), "test", "test"); - // } - // }); // 3rd line: description Label lbl = toolkit.createLabel(parent, "Description"); @@ -147,8 +141,10 @@ public class ItemTemplateTitleComposite extends Composite { // set new alias Node newAlias = definedAliases.get(selIndex); - akbNode.setProperty(AkbNames.AKB_USED_CONNECTOR, - newAlias.getPath()); + + // Only relies on the alias + akbNode.setProperty(AkbNames.AKB_USED_CONNECTOR, newAlias + .getProperty(Property.JCR_TITLE).getString()); part.markDirty(); } catch (RepositoryException e) { throw new AkbException( @@ -161,7 +157,15 @@ public class ItemTemplateTitleComposite extends Composite { } private void refreshTypeCmbValues() { - List newAliases = AkbJcrUtils.getDefinedAliasForNode(akbNode); + List newAliases; + try { + newAliases = JcrUtils.nodeIteratorToList(akbService + .getDefinedAliases(AkbJcrUtils.getCurrentTemplate(akbNode), + AkbJcrUtils.getAliasTypeForNode(akbNode))); + } catch (RepositoryException e) { + throw new AkbException("Unable to get defined aliases for node " + + akbNode, e); + } boolean hasChanged = false; // manually ckeck if something has changed if (definedAliases == null diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbItemTemplateEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbItemTemplateEditor.java index dbe0b684c..03a821691 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbItemTemplateEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbItemTemplateEditor.java @@ -23,7 +23,7 @@ public abstract class AkbItemTemplateEditor extends AbstractAkbNodeEditor { parent.setLayout(AkbUiUtils.gridLayoutNoBorder()); // First line main info ItemTemplateTitleComposite ittCmp = new ItemTemplateTitleComposite( - parent, SWT.NO_FOCUS, getToolkit(), managedForm, getAkbNode()); + parent, SWT.NO_FOCUS, getToolkit(), managedForm, getAkbNode(), getAkbService()); GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); gd.minimumHeight = 250; ittCmp.setLayoutData(gd); diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbNodeEditorInput.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbNodeEditorInput.java index be77afe31..8e51c1405 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbNodeEditorInput.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbNodeEditorInput.java @@ -6,19 +6,33 @@ import org.eclipse.ui.IPersistableElement; /** * Editor input for all editors that display info on a given AKB JCR Node. - * Relies on the Jcr ID + * + * Relies on the Jcr ID, */ public class AkbNodeEditorInput implements IEditorInput { + private final String envJcrId; + // Only null if current node is a environment (active or template) private final String jcrId; - /** the Jcr ID cannot be null */ - public AkbNodeEditorInput(String jcrId) { + /** + * the Env Jcr ID cannot be null, JcrId can only be null if current node is + * an environment (active or template) + */ + public AkbNodeEditorInput(String envJcrId, String jcrId) { + this.envJcrId = envJcrId; this.jcrId = jcrId; } public String getIdentifier() { - return jcrId; + if (jcrId == null) + return envJcrId; + else + return jcrId; + } + + public String getEnvIdentifier() { + return envJcrId; } public boolean exists() { @@ -58,7 +72,8 @@ public class AkbNodeEditorInput implements IEditorInput { if (getClass() != obj.getClass()) return false; AkbNodeEditorInput other = (AkbNodeEditorInput) obj; - if (!jcrId.equals(other.getIdentifier())) + if (!jcrId.equals(other.getIdentifier()) + || !envJcrId.equals(other.getEnvIdentifier())) return false; return true; } diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/ConnectorAliasEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/ConnectorAliasEditor.java index a69fdcf3a..95bfa0c58 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/ConnectorAliasEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/ConnectorAliasEditor.java @@ -1,25 +1,22 @@ package org.argeo.slc.akb.ui.editors; +import javax.jcr.Node; 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; import org.argeo.slc.akb.ui.AkbUiPlugin; import org.argeo.slc.akb.ui.AkbUiUtils; import org.argeo.slc.akb.utils.AkbJcrUtils; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Text; @@ -36,18 +33,25 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { public final static String ID = AkbUiPlugin.PLUGIN_ID + ".connectorAliasEditor"; - private String[] connectorTypesLbl = new String[] { "JDBC", "SSH", "JCR" }; - private String[] connectorTypes = new String[] { - AkbTypes.AKB_JDBC_CONNECTOR, AkbTypes.AKB_SSH_CONNECTOR, - AkbTypes.AKB_JCR_CONNECTOR }; - private IManagedForm managedForm; + private Node activeConnector; /* CONTENT CREATION */ @Override public void populateMainPage(Composite parent, IManagedForm managedForm) { parent.setLayout(AkbUiUtils.gridLayoutNoBorder()); + + // TODO clean this + // Initialization this.managedForm = managedForm; + // enable dynamic change of the active connector + try { + activeConnector = getAkbNode().getNode( + AkbNames.AKB_DEFAULT_TEST_CONNECTOR); + } catch (RepositoryException e) { + throw new AkbException("unable to retrieve active connector node", + e); + } // First line main info Composite firstLine = getToolkit() @@ -64,22 +68,18 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { } private void createConnectorAliasInfoCmp(Composite parent) { - parent.setLayout(new GridLayout(4, false)); - - // first line: connector type and name - getToolkit().createLabel(parent, "Connector Type"); - final Combo typeCmb = new Combo(parent, SWT.READ_ONLY); - typeCmb.setItems(connectorTypesLbl); + parent.setLayout(new GridLayout(2, false)); - getToolkit().createLabel(parent, "Name"); + // Name final Text titleTxt = getToolkit().createText(parent, "", SWT.BORDER); - GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); + GridData gd = new GridData(SWT.FILL, SWT.TOP, false, false); + gd.minimumWidth = 200; + gd.widthHint = 200; titleTxt.setLayoutData(gd); - // 2nd line: description - getToolkit().createLabel(parent, "Short Description"); + // Description final Text descTxt = getToolkit().createText(parent, "", SWT.BORDER); - gd = new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1); + gd = new GridData(SWT.FILL, SWT.TOP, true, false); descTxt.setLayoutData(gd); // Part Management @@ -88,12 +88,9 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { super.refresh(); // update display value AkbUiUtils.refreshFormTextWidget(titleTxt, getAkbNode(), - Property.JCR_TITLE); + Property.JCR_TITLE, "Name"); AkbUiUtils.refreshFormTextWidget(descTxt, getAkbNode(), - Property.JCR_DESCRIPTION); - typeCmb.select(getCurrTypeIndex()); - typeCmb.setEnabled(AkbJcrUtils - .isNodeCheckedOutByMe(getAkbNode())); + Property.JCR_DESCRIPTION, "Short description"); } }; // Listeners @@ -102,48 +99,12 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { AkbUiUtils.addTextModifyListener(descTxt, getAkbNode(), Property.JCR_DESCRIPTION, part); - typeCmb.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent event) { - - try { // TODO enhance this - // retrieve old and new node type - int oldIndex = getCurrTypeIndex(); - int selIndex = typeCmb.getSelectionIndex(); - - // insure something has really been modified - if (selIndex < 0 || oldIndex == selIndex) - return; - - // remove old mixin, add new and notify form - if (oldIndex > -1) - getAkbNode().removeMixin(connectorTypes[oldIndex]); - getAkbNode().addMixin(connectorTypes[selIndex]); - part.markDirty(); - } catch (RepositoryException e) { - throw new AkbException( - "Error while updating connector type", e); - } - } - }); managedForm.addPart(part); } - private int getCurrTypeIndex() { - try { - int oldIndex = -1; - for (int i = 0; i < connectorTypes.length; i++) { - if (getAkbNode().isNodeType(connectorTypes[i])) { - oldIndex = i; - break; - - } - } - return oldIndex; - } catch (RepositoryException e) { - throw new AkbException("Error while getting connector type", e); - } - + protected void updatePartNameAndToolTip() { + super.updatePartNameAndToolTip(); + // TODO update editor image } private void createDefaultTestConnectorCmp(Composite parent) { @@ -155,8 +116,8 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { group.setText(groupTitle); group.setLayout(AkbUiUtils.gridLayoutNoBorder()); - // 1st line: the URL + // 1st line: the URL Composite firstLine = getToolkit().createComposite(group); firstLine.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); firstLine.setLayout(new GridLayout(2, false)); @@ -179,32 +140,34 @@ public class ConnectorAliasEditor extends AbstractAkbNodeEditor { public void refresh() { super.refresh(); // update display value - AkbUiUtils.refreshFormTextWidget(urlTxt, getAkbNode(), + AkbUiUtils.refreshFormTextWidget(urlTxt, activeConnector, AkbNames.AKB_CONNECTOR_URL); - AkbUiUtils.refreshFormTextWidget(userTxt, getAkbNode(), + AkbUiUtils.refreshFormTextWidget(userTxt, activeConnector, AkbNames.AKB_CONNECTOR_USER); } }; // Listeners - AkbUiUtils.addTextModifyListener(urlTxt, getAkbNode(), + AkbUiUtils.addTextModifyListener(urlTxt, activeConnector, AkbNames.AKB_CONNECTOR_URL, part); - AkbUiUtils.addTextModifyListener(userTxt, getAkbNode(), + AkbUiUtils.addTextModifyListener(userTxt, activeConnector, AkbNames.AKB_CONNECTOR_USER, part); testBtn.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { boolean testSuccesfull; + try { - testSuccesfull = getAkbService() - .testConnector(getAkbNode()); + testSuccesfull = getAkbService().testConnector( + activeConnector); } catch (Exception e1) { testSuccesfull = false; ErrorFeedback.show("Cannot test connection", e1); } - String name = AkbJcrUtils.get(getAkbNode(), Property.JCR_TITLE); - String url = AkbJcrUtils.get(getAkbNode(), + String name = AkbJcrUtils.get(activeConnector, + Property.JCR_TITLE); + String url = AkbJcrUtils.get(activeConnector, AkbNames.AKB_CONNECTOR_URL); String msg = "to " + name + " (" + url + ")"; diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/EnvTemplateEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/EnvTemplateEditor.java index 53beb7460..c7908f5fb 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/EnvTemplateEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/EnvTemplateEditor.java @@ -1,11 +1,38 @@ package org.argeo.slc.akb.ui.editors; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.observation.Event; +import javax.jcr.observation.ObservationManager; + +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; +import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.AkbTypes; import org.argeo.slc.akb.ui.AkbUiPlugin; import org.argeo.slc.akb.ui.AkbUiUtils; +import org.argeo.slc.akb.ui.commands.OpenAkbNodeEditor; +import org.argeo.slc.akb.ui.composites.ConnectorAliasSmallComposite; import org.argeo.slc.akb.ui.composites.MixTitleComposite; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.IManagedForm; /** @@ -16,14 +43,180 @@ public class EnvTemplateEditor extends AbstractAkbNodeEditor { public final static String ID = AkbUiPlugin.PLUGIN_ID + ".envTemplateEditor"; + // Observer + private final static String[] observedNodes = { AkbTypes.AKB_CONNECTOR_FOLDER }; + private ConnectorObserver connectorObserver; + /* CONTENT CREATION */ @Override public void populateMainPage(Composite parent, IManagedForm managedForm) { - parent.setLayout(AkbUiUtils.gridLayoutNoBorder()); + parent.setLayout(new GridLayout()); // First line main info MixTitleComposite mixTitleCmp = new MixTitleComposite(parent, SWT.NO_FOCUS, getToolkit(), managedForm, getAkbNode()); - mixTitleCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); + gd.heightHint = 200; + mixTitleCmp.setLayoutData(gd); + + // Second line : the defined editor + Group group = new Group(parent, SWT.NONE); + group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + getToolkit().adapt(group, false, false); + String groupTitle = "Connector Aliases"; + group.setText(groupTitle); + populateDisplayConnectorPanel(managedForm, group, getAkbNode()); + + // add context menu + MenuManager menuManager = new MenuManager(); + Menu menu = menuManager.createContextMenu(group); + menuManager.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + aboutToShow(manager); + } + }); + group.setMenu(menu); + menuManager.setRemoveAllWhenShown(true); + } + + private void aboutToShow(IMenuManager menu) { + try { + // initialization + String submenuID = "subMenu.addAlias"; + IWorkbenchWindow window = AkbUiPlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow(); + Node connectorParent = getAkbNode(); + IContributionItem ici = menu.find(submenuID); + if (ici != null) + menu.remove(ici); + Map params = new HashMap(); + params.put(OpenAkbNodeEditor.PARAM_PARENT_NODE_JCR_ID, + connectorParent.getIdentifier()); + params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, + AkbTypes.AKB_CONNECTOR_ALIAS); + + MenuManager subMenu = new MenuManager("Add connector alias", + submenuID); + // JDBC + Map tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_SUBTYPE, + AkbTypes.AKB_JDBC_CONNECTOR); + String currItemId = "cmd.createJDBCAlias"; + IContributionItem currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(subMenu, window, + currItemId, OpenAkbNodeEditor.ID, "JDBC", null, tmpParams)); + + // SSH + tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_SUBTYPE, + AkbTypes.AKB_SSH_CONNECTOR); + currItemId = "cmd.createSSHAlias"; + currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(subMenu, window, + currItemId, OpenAkbNodeEditor.ID, "SSH", null, tmpParams)); + + menu.add(subMenu); + + } catch (RepositoryException e) { + throw new AkbException("Unable to refresh context menu", e); + } + } + + /** Manage display and update of defined connector aliases */ + public void populateDisplayConnectorPanel(final IManagedForm managedForm, + final Composite panel, final Node entity) { + GridLayout gl = AkbUiUtils.gridLayoutNoBorder(); + gl.marginTop = 10; + panel.setLayout(gl); + + final Map connectorsCmps = new HashMap(); + AbstractFormPart formPart = new AbstractFormPart() { + public void refresh() { + try { + super.refresh(); + // first: initialise composite for new connectors + Node connectorPar = getAkbNode().getNode( + AkbTypes.AKB_CONNECTOR_FOLDER); + NodeIterator ni = connectorPar.getNodes(); + while (ni.hasNext()) { + Node currNode = ni.nextNode(); + String currJcrId = currNode.getIdentifier(); + if (!connectorsCmps.containsKey(currJcrId)) { + Composite currCmp = new ConnectorAliasSmallComposite( + panel, SWT.NO_FOCUS, getToolkit(), + managedForm, currNode, getAkbService()); + currCmp.setLayoutData(new GridData(SWT.FILL, + SWT.TOP, true, false)); + connectorsCmps.put(currJcrId, currCmp); + } + } + + // then remove necessary composites + Session session = connectorPar.getSession(); + for (String jcrId : connectorsCmps.keySet()) { + // TODO: enhance this + Composite currCmp = connectorsCmps.get(jcrId); + try { + session.getNodeByIdentifier(jcrId); + } catch (ItemNotFoundException infe) { + currCmp.dispose(); + } + } + panel.layout(); + } catch (RepositoryException e) { + throw new AkbException("Cannot refresh connectors group", e); + } + } + }; + formPart.refresh(); + managedForm.addPart(formPart); + + // Initialize observer + try { + ObservationManager observationManager = getSession().getWorkspace() + .getObservationManager(); + connectorObserver = new ConnectorObserver(panel.getDisplay(), + formPart); + // observe tree changes under All results + observationManager.addEventListener(connectorObserver, + Event.NODE_ADDED | Event.NODE_REMOVED, getAkbNode() + .getNode(AkbTypes.AKB_CONNECTOR_FOLDER).getPath(), + true, null, observedNodes, false); + } catch (RepositoryException e) { + throw new AkbException("Cannot register listeners", e); + } + + } + + class ConnectorObserver extends AsyncUiEventListener { + + private AbstractFormPart formPart; + + public ConnectorObserver(Display display, AbstractFormPart formPart) { + super(display); + this.formPart = formPart; + } + + @Override + protected Boolean willProcessInUiThread(List events) + throws RepositoryException { + return true; + } + + protected void onEventInUiThread(List events) + throws RepositoryException { + try { + formPart.refresh(); + } catch (Exception e) { + // silently fail + e.printStackTrace(); + } + } } @Override 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 index 65c59d20c..c9f74b0a5 100644 --- 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 @@ -35,7 +35,9 @@ import org.eclipse.ui.forms.widgets.ScrolledForm; /** Test JDBC. */ public class JdbcTestPage extends FormPage implements AkbNames { - private Node node; + private Node currItem; + // A template or an active environment + private Node currEnv; private AkbService akbService; private TableViewer viewer = null; @@ -44,10 +46,11 @@ public class JdbcTestPage extends FormPage implements AkbNames { private PreparedStatement statement; public JdbcTestPage(AkbService akbService, FormEditor editor, String id, - String title, Node node) { + String title, Node currEnv, Node currItem) { super(editor, id, title); this.akbService = akbService; - this.node = node; + this.currItem = currItem; + this.currEnv = currEnv; } protected void createFormContent(IManagedForm managedForm) { @@ -67,8 +70,8 @@ public class JdbcTestPage extends FormPage implements AkbNames { viewer.setContentProvider(contentProvider); // viewer.setLabelProvider(new ColumnLabelProvider(){}); - statement = akbService.prepareJdbcQuery(node); - PrivilegedJob job = new PrivilegedJob("Execute query on " + node) { + statement = akbService.prepareJdbcQuery(currEnv, currItem); + PrivilegedJob job = new PrivilegedJob("Execute query on " + currItem) { @Override protected IStatus doRun(IProgressMonitor progressMonitor) { @@ -84,7 +87,7 @@ public class JdbcTestPage extends FormPage implements AkbNames { }); return Status.OK_STATUS; } catch (SQLException e) { - throw new SlcException("Cannot execute " + node, e); + throw new SlcException("Cannot execute " + currItem, e); } } }; diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/providers/TemplatesTreeContentProvider.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/providers/TemplatesTreeContentProvider.java index 1f39f33d8..e35302864 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/providers/TemplatesTreeContentProvider.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/providers/TemplatesTreeContentProvider.java @@ -15,13 +15,15 @@ */ package org.argeo.slc.akb.ui.providers; +import java.util.ArrayList; import java.util.List; import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; -import org.argeo.jcr.JcrUtils; import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.AkbTypes; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; @@ -54,8 +56,15 @@ public class TemplatesTreeContentProvider implements ITreeContentProvider { public Object[] getChildren(Object parent) { try { - List nodes = JcrUtils.nodeIteratorToList(((Node) parent) - .getNodes()); + NodeIterator ni = ((Node) parent).getNodes(); + List nodes = new ArrayList(); + + while (ni.hasNext()) { + Node currNode = ni.nextNode(); + if (!currNode.isNodeType(AkbTypes.AKB_CONNECTOR_FOLDER)) + nodes.add(currNode); + } + return nodes.toArray(); } catch (RepositoryException e) { throw new AkbException("Error while getting children nodes", e); @@ -64,6 +73,7 @@ public class TemplatesTreeContentProvider implements ITreeContentProvider { public boolean hasChildren(Object parent) { try { + // refine this return ((Node) parent).hasNodes(); } catch (RepositoryException e) { throw new AkbException("Error while checking children nodes", e); diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/utils/Refreshable.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/utils/Refreshable.java new file mode 100644 index 000000000..f7c01daaa --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/utils/Refreshable.java @@ -0,0 +1,11 @@ +package org.argeo.slc.akb.ui.utils; + +/** + * WorkbenchPart should implement this interface to enable refresh command to + * refresh them + */ +public interface Refreshable { + + public void forceRefresh(Object object); + +} diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbTemplatesTreeView.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbTemplatesTreeView.java index 399f128f5..b1245f124 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbTemplatesTreeView.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbTemplatesTreeView.java @@ -41,11 +41,12 @@ import org.argeo.slc.akb.ui.commands.DeleteAkbNodes; import org.argeo.slc.akb.ui.commands.OpenAkbNodeEditor; import org.argeo.slc.akb.ui.providers.AkbTreeLabelProvider; import org.argeo.slc.akb.ui.providers.TemplatesTreeContentProvider; +import org.argeo.slc.akb.ui.utils.Refreshable; +import org.argeo.slc.akb.ui.views.AkbTemplatesTreeView.ViewDoubleClickListener; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; @@ -56,15 +57,13 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.menus.CommandContributionItem; -import org.eclipse.ui.menus.CommandContributionItemParameter; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.services.IServiceLocator; /** SLC generic JCR Result tree view. */ -public class AkbTemplatesTreeView extends ViewPart { +public class AkbTemplatesTreeView extends ViewPart implements Refreshable { // private final static Log log = - // LogFactory.getLog(JcrResultTreeView.class); + // LogFactory.getLog(AkbTemplatesTreeView.class); public final static String ID = AkbUiPlugin.PLUGIN_ID + ".akbTemplatesTreeView"; @@ -73,38 +72,18 @@ public class AkbTemplatesTreeView extends ViewPart { private Session session; // This page widgets - private TreeViewer resultTreeViewer; + private TreeViewer envTreeViewer; // Usefull business objects private Node templatesParentNode; // Observer - private EventListener allResultsObserver = null; - private final static String[] observedNodeTypesUnderAllResults = { + private EventListener akbNodesObserver = null; + private final static String[] observedNodeTypes = { AkbTypes.AKB_ENV_TEMPLATE, AkbTypes.AKB_CONNECTOR_ALIAS, AkbTypes.AKB_ITEM, AkbTypes.AKB_ITEM_FOLDER, AkbTypes.AKB_CONNECTOR_FOLDER }; - // private EventListener myResultsObserver = null; - // private EventListener allResultsObserver = null; - // - // // under My Results - // private final static String[] observedNodeTypesUnderMyResult = { - // SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER, - // SlcTypes.SLC_MY_RESULT_ROOT_FOLDER }; - // - // private final static String[] observedNodeTypesUnderAllResults = { - // SlcTypes.SLC_TEST_RESULT, NodeType.NT_UNSTRUCTURED }; - // - // private boolean isResultFolder = false; - - // /** - // * To be overridden to adapt size of form and result frames. - // */ - // protected int[] getWeights() { - // return new int[] { 70, 30 }; - // } - private void initialize() { try { templatesParentNode = session @@ -118,8 +97,8 @@ public class AkbTemplatesTreeView extends ViewPart { public void createPartControl(Composite parent) { initialize(); - resultTreeViewer = createResultsTreeViewer(parent); - resultTreeViewer.setInput(initializeResultTree()); + envTreeViewer = createResultsTreeViewer(parent); + envTreeViewer.setInput(initializeResultTree()); // parent.setLayout(new FillLayout()); // // Main layout @@ -202,66 +181,18 @@ public class AkbTemplatesTreeView extends ViewPart { ObservationManager observationManager = session.getWorkspace() .getObservationManager(); - allResultsObserver = new AllResultsObserver(viewer.getTree() + akbNodesObserver = new AkbNodesObserver(viewer.getTree() .getDisplay()); - - // observe tree changes under All results - observationManager.addEventListener(allResultsObserver, + observationManager.addEventListener(akbNodesObserver, Event.NODE_ADDED | Event.NODE_REMOVED, templatesParentNode.getPath(), true, null, - observedNodeTypesUnderAllResults, false); + observedNodeTypes, false); } catch (RepositoryException e) { throw new AkbException("Cannot register listeners", e); } - - // add change listener to display TestResult information in the property - // viewer - // viewer.addSelectionChangedListener(new MySelectionChangedListener()); return viewer; } - class AllResultsObserver extends AsyncUiEventListener { - - public AllResultsObserver(Display display) { - super(display); - } - - @Override - protected Boolean willProcessInUiThread(List events) - throws RepositoryException { - // unfiltered for the time being - return true; - } - - protected void onEventInUiThread(List events) - throws RepositoryException { - boolean fullRefresh = false; - - eventLoop: for (Event event : events) { - String currPath = event.getPath(); - if (session.nodeExists(currPath)) { - Node node = session.getNode(currPath); - if (node.isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) { - fullRefresh = true; - break eventLoop; - } - } - } - - Object[] visibles = resultTreeViewer.getExpandedElements(); - if (fullRefresh) - resultTreeViewer.setInput(initializeResultTree()); - else - resultTreeViewer.refresh(); - - resultTreeViewer.setExpandedElements(visibles); - } - } - - // Detailed property viewer - // protected TableViewer createPropertiesViewer(Composite parent) { - // } - @Override public void setFocus() { } @@ -270,13 +201,11 @@ public class AkbTemplatesTreeView extends ViewPart { try { NodeIterator ni = templatesParentNode.getNodes(); List templates = new ArrayList(); - while (ni.hasNext()) { Node currNode = ni.nextNode(); if (currNode.isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) templates.add(currNode); } - Node[] templateArr = templates.toArray(new Node[templates.size()]); return templateArr; } catch (RepositoryException re) { @@ -285,7 +214,14 @@ public class AkbTemplatesTreeView extends ViewPart { } } - // Manage context menu + @Override + public void forceRefresh(Object object) { + envTreeViewer.setInput(initializeResultTree()); + } + + // /////////////////////////// + // CONTEXT MENU MANAGEMENT + /** * Defines the commands that will pop up in the context menu. **/ @@ -295,38 +231,39 @@ public class AkbTemplatesTreeView extends ViewPart { try { // Build conditions - Node selected = (Node) ((IStructuredSelection) resultTreeViewer - .getSelection()).getFirstElement(); + IStructuredSelection selection = (IStructuredSelection) envTreeViewer + .getSelection(); + + Node selected = (Node) selection.getFirstElement(); boolean hasSelection = selected != null; + boolean isTemplate = hasSelection ? selected + .isNodeType(AkbTypes.AKB_ENV_TEMPLATE) : false; boolean isParentItemsFolder = hasSelection ? selected .isNodeType(AkbTypes.AKB_ITEM_FOLDER) : false; - boolean isParentConnectorsFolder = hasSelection ? selected - .isNodeType(AkbTypes.AKB_CONNECTOR_FOLDER) : false; - boolean isDeletable = hasSelection ? !(selected.getParent() - .isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) : false; + // boolean isParentConnectorsFolder = hasSelection ? selected + // .isNodeType(AkbTypes.AKB_CONNECTOR_FOLDER) : false; + boolean isDeletable = hasSelection ? true : false; // Add Connector Alias Map params = new HashMap(); - if (hasSelection) + if (hasSelection && isTemplate) params.put(OpenAkbNodeEditor.PARAM_PARENT_NODE_JCR_ID, selected.getIdentifier()); params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_CONNECTOR_ALIAS); - refreshParameterizedCommand(menuManager, window, - "cmd.addConnector", OpenAkbNodeEditor.ID, - "Add connector Alias", null, isParentConnectorsFolder, - params); - // Add Item + // Connector Alias submenu + refreshAliasesSubmenu(menuManager, window, "menu.aliasesSubmenu", + "Add Connector Alias", isTemplate, params); + + // Item Submenu params = new HashMap(); if (hasSelection) params.put(OpenAkbNodeEditor.PARAM_PARENT_NODE_JCR_ID, selected.getIdentifier()); - params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_ITEM); - refreshParameterizedCommand(menuManager, window, "cmd.addItem", - OpenAkbNodeEditor.ID, "Add item", null, - isParentItemsFolder, params); + refreshItemsSubmenu(menuManager, window, "menu.itemsSubmenu", + "Add Item", isParentItemsFolder || isTemplate, params); // Add Item Folder params = new HashMap(); @@ -335,18 +272,19 @@ public class AkbTemplatesTreeView extends ViewPart { selected.getIdentifier()); params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_ITEM_FOLDER); - refreshParameterizedCommand(menuManager, window, + AkbUiUtils.refreshParameterizedCommand(menuManager, window, "cmd.addItemFolder", OpenAkbNodeEditor.ID, - "Add item folder", null, isParentItemsFolder, params); + "Add item folder", null, isParentItemsFolder || isTemplate, + params); // Delete Item params = new HashMap(); if (hasSelection) params.put(DeleteAkbNodes.PARAM_NODE_JCR_ID, selected.getIdentifier()); - refreshParameterizedCommand(menuManager, window, "cmd.deleteItem", - DeleteAkbNodes.ID, "Delete selected item(s)", null, - isDeletable, params); + AkbUiUtils.refreshParameterizedCommand(menuManager, window, + "cmd.deleteItem", DeleteAkbNodes.ID, + "Delete selected item(s)", null, isDeletable, params); // create template params = new HashMap(); @@ -354,9 +292,10 @@ public class AkbTemplatesTreeView extends ViewPart { templatesParentNode.getIdentifier()); params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_ENV_TEMPLATE); - refreshParameterizedCommand(menuManager, window, + AkbUiUtils.refreshParameterizedCommand(menuManager, window, "cmd.createTemplate", OpenAkbNodeEditor.ID, - "Create new template...", null, true, params); + "Create new template...", null, + !hasSelection || isTemplate, params); } catch (RepositoryException re) { throw new AkbException("Error while refreshing context menu", re); @@ -364,41 +303,186 @@ public class AkbTemplatesTreeView extends ViewPart { } /** - * Commodities the refresh of a single command with a map of parameters in a - * Menu.aboutToShow method to simplify further development + * + * refreshes submenu with various connector types * * @param menuManager * @param locator - * @param cmdId + * @param itemId * @param label - * @param iconPath - * @param showCommand + * @param isVisible + * @param params */ - private void refreshParameterizedCommand(IMenuManager menuManager, - IServiceLocator locator, String itemId, String cmdId, String label, - ImageDescriptor icon, boolean showCommand, - Map params) { + private void refreshItemsSubmenu(IMenuManager menuManager, + IServiceLocator locator, String itemId, String label, + boolean isVisible, Map params) { + + // clean IContributionItem ici = menuManager.find(itemId); if (ici != null) menuManager.remove(ici); - CommandContributionItemParameter contributionItemParameter = new CommandContributionItemParameter( - locator, itemId, cmdId, SWT.PUSH); - if (showCommand) { - // Set Params - contributionItemParameter.label = label; - contributionItemParameter.icon = icon; + MenuManager subMenu = new MenuManager(label, itemId); + + // JDBC Query + Map tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, + AkbTypes.AKB_JDBC_QUERY); + String currItemId = "cmd.createJDBCQuery"; + IContributionItem currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(menuManager, locator, + currItemId, OpenAkbNodeEditor.ID, "JDBC", null, tmpParams)); + + // SSH COMMAND + tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, + AkbTypes.AKB_SSH_COMMAND); + currItemId = "cmd.createSSHCommand"; + currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(menuManager, locator, + currItemId, OpenAkbNodeEditor.ID, "SSH Command", null, + tmpParams)); + + // SSH FILE + tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_SSH_FILE); + currItemId = "cmd.createSSHFile"; + currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(menuManager, locator, + currItemId, OpenAkbNodeEditor.ID, "SSH File", null, tmpParams)); + + // refresh + menuManager.add(subMenu); + subMenu.setVisible(isVisible); + } + + /** + * + * refreshes submenu with various connector types + * + * @param menuManager + * @param locator + * @param itemId + * @param label + * @param isVisible + * @param params + */ + private void refreshAliasesSubmenu(IMenuManager menuManager, + IServiceLocator locator, String itemId, String label, + boolean isVisible, Map params) { - if (params != null) - contributionItemParameter.parameters = params; + // clean + IContributionItem ici = menuManager.find(itemId); + if (ici != null) + menuManager.remove(ici); - CommandContributionItem cci = new CommandContributionItem( - contributionItemParameter); - menuManager.add(cci); - } + // TODO use dynamic contribution to dynamically retrieve specific + // connector types + // CompoundContributionItem comConI = new MyCompoundCI(menuManager, + // locator, itemId); + MenuManager subMenu = new MenuManager(label, itemId); + + // JDBC + Map tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_SUBTYPE, + AkbTypes.AKB_JDBC_CONNECTOR); + String currItemId = "cmd.createJDBCAlias"; + IContributionItem currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(menuManager, locator, + currItemId, OpenAkbNodeEditor.ID, "JDBC", null, tmpParams)); + + // SSH + tmpParams = new HashMap(); + tmpParams.putAll(params); + tmpParams.put(OpenAkbNodeEditor.PARAM_NODE_SUBTYPE, + AkbTypes.AKB_SSH_CONNECTOR); + currItemId = "cmd.createSSHAlias"; + currItem = subMenu.find(currItemId); + if (currItem != null) + subMenu.remove(currItem); + subMenu.add(AkbUiUtils.createContributionItem(menuManager, locator, + currItemId, OpenAkbNodeEditor.ID, "SSH", null, tmpParams)); + + // refresh + menuManager.add(subMenu); + subMenu.setVisible(isVisible); } + // private class MyCompoundCI extends CompoundContributionItem { + // private IMenuManager menuManager; + // private IServiceLocator locator; + // + // public MyCompoundCI(IMenuManager menuManager, IServiceLocator locator, + // String itemId) { + // super(itemId); + // this.menuManager = menuManager; + // this.locator = locator; + // } + // + // @Override + // protected IContributionItem[] getContributionItems() { + // + // CommandContributionItem[] submenu = new CommandContributionItem[2]; + // submenu[0] = createContributionItem(menuManager, locator, "uid.1", + // OpenAkbNodeEditor.ID, "test1" + System.currentTimeMillis(), + // null, null); + // submenu[1] = createContributionItem(menuManager, locator, "uid.2", + // OpenAkbNodeEditor.ID, "test2", null, null); + // return submenu; + // } + // } + /* INNER CLASSES */ + private class AkbNodesObserver extends AsyncUiEventListener { + + public AkbNodesObserver(Display display) { + super(display); + } + + @Override + protected Boolean willProcessInUiThread(List events) + throws RepositoryException { + // unfiltered for the time being + return true; + } + + protected void onEventInUiThread(List events) + throws RepositoryException { + boolean fullRefresh = false; + + eventLoop: for (Event event : events) { + String currPath = event.getPath(); + if (session.nodeExists(currPath)) { + Node node = session.getNode(currPath); + if (node.isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) { + fullRefresh = true; + break eventLoop; + } + } + } + + Object[] visibles = envTreeViewer.getExpandedElements(); + if (fullRefresh) + envTreeViewer.setInput(initializeResultTree()); + else + envTreeViewer.refresh(); + + envTreeViewer.setExpandedElements(visibles); + } + } + class ViewDoubleClickListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent evt) { Object obj = ((IStructuredSelection) evt.getSelection()) diff --git a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbNames.java b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbNames.java index 76248a842..7be2b1148 100644 --- a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbNames.java +++ b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbNames.java @@ -17,7 +17,11 @@ public interface AkbNames { /* CONNECTOR PROPERTIES */ public final static String AKB_CONNECTOR_URL = "akb:connectorUrl"; + public final static String AKB_CONNECTOR_ALIAS_NAME = "akb:connectorName"; public final static String AKB_CONNECTOR_USER = "akb:connectorUser"; + // Alias specific + public final static String AKB_DEFAULT_TEST_CONNECTOR = "defaultTestConnector"; + public final static String AKB_CONNECTOR_TYPE = "akb:connectorType"; /* ITEMS PROPERTIES */ public final static String AKB_USED_CONNECTOR = "akb:usedConnector"; diff --git a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbService.java b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbService.java index 8a16c63d3..869758175 100644 --- a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbService.java +++ b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbService.java @@ -3,25 +3,57 @@ package org.argeo.slc.akb; import java.sql.PreparedStatement; import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; /** Provides method interfaces to manage an AKB repository */ public interface AkbService { - /** Creates a preconfigured AKB Template */ + /** Creates a pre-configured AKB Template */ public Node createAkbTemplate(Node parent, String name) throws RepositoryException; + /** Creates a new pre-configured AKB connector Alias for the given template */ + public Node createConnectorAlias(Node templateNode, String name, + String connectorType) throws RepositoryException; + + /** + * @param templateNode + * @param connectorType + * if null, returns all defined connector for this template + * @return + * @throws RepositoryException + */ + public NodeIterator getDefinedAliases(Node templateNode, + String connectorType) throws RepositoryException; + + /** + * @param envNode + * an environment or a template + * @param aliasName + * the alias of the node to get + * @return + * @throws RepositoryException + */ + public Node getConnectorByAlias(Node envNode, String aliasName) + throws RepositoryException; + /** * Shortcut to perform whatever test on a given connector only to check if * URL is correctly defined, if the target system is there and if the * current user has the sufficient credentials to connect + * + * If no active environment is defined, try to */ public boolean testConnector(Node connector); - public PreparedStatement prepareJdbcQuery(Node node); + /** + * If no active environment is defined, tries to execute query with default + * connector defined for the template + */ + public PreparedStatement prepareJdbcQuery(Node activeEnvironment, Node node); - public String executeCommand(Node node); + public String executeCommand(Node activeEnvironment, Node node); - public String retrieveFile(Node node); -} + public String retrieveFile(Node activeEnvironment, Node node); +} \ No newline at end of file diff --git a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbTypes.java b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbTypes.java index 349e419ee..20c8e072a 100644 --- a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbTypes.java +++ b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/AkbTypes.java @@ -10,7 +10,6 @@ public interface AkbTypes { public final static String AKB_ENV = "akb:env"; // Connectors - public final static String AKB_CONNECTOR_FOLDER = "akb:connectorFolder"; public final static String AKB_CONNECTOR = "akb:connector"; public final static String AKB_CONNECTOR_ALIAS = "akb:connectorAlias"; 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 ba7b6cc04..bd79ace0f 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 @@ -10,10 +10,19 @@ import java.util.Map; import javax.annotation.Resource; import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.query.QueryManager; +import javax.jcr.query.QueryResult; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.Ordering; +import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.QueryObjectModelConstants; +import javax.jcr.query.qom.QueryObjectModelFactory; +import javax.jcr.query.qom.Selector; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; @@ -103,7 +112,6 @@ public class AkbServiceImpl implements AkbService, AkbNames { 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); @@ -112,16 +120,113 @@ public class AkbServiceImpl implements AkbService, AkbNames { 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 + @Override + public Node createConnectorAlias(Node templateNode, String name, + String connectorType) throws RepositoryException { + Node parent = JcrUtils.mkdirs(templateNode, + AkbTypes.AKB_CONNECTOR_FOLDER, AkbTypes.AKB_CONNECTOR_FOLDER); + Node newConnector = parent.addNode(name, AkbTypes.AKB_CONNECTOR_ALIAS); + newConnector.setProperty(Property.JCR_TITLE, name); + newConnector.setProperty(AkbNames.AKB_CONNECTOR_TYPE, connectorType); + + // Node defaultConnector = + Node defaultConn = newConnector.addNode( + AkbNames.AKB_DEFAULT_TEST_CONNECTOR, connectorType); + defaultConn.setProperty(AkbNames.AKB_CONNECTOR_ALIAS_NAME, name); + return newConnector; + } + + @Override + public NodeIterator getDefinedAliases(Node itemTemplate, + String connectorType) throws RepositoryException { + try { + Session session = itemTemplate.getSession(); + QueryManager queryManager = session.getWorkspace() + .getQueryManager(); + QueryObjectModelFactory factory = queryManager.getQOMFactory(); + + Selector source = factory.selector(AkbTypes.AKB_CONNECTOR_ALIAS, + AkbTypes.AKB_CONNECTOR_ALIAS); + Constraint defaultC = factory.descendantNode( + source.getSelectorName(), itemTemplate.getPath()); + + if (connectorType != null) { + Constraint connType = factory.comparison(factory.propertyValue( + source.getSelectorName(), AkbNames.AKB_CONNECTOR_TYPE), + QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO, + factory.literal(session.getValueFactory().createValue( + connectorType))); + defaultC = factory.and(defaultC, connType); + } + + // Order by default by JCR TITLE + // TODO check if node definition has MIX_TITLE mixin + // TODO Apparently case insensitive ordering is not implemented in + // current used JCR implementation + Ordering order = factory + .ascending(factory.upperCase(factory.propertyValue( + source.getSelectorName(), Property.JCR_TITLE))); + QueryObjectModel query; + query = factory.createQuery(source, defaultC, + new Ordering[] { order }, null); + QueryResult result = query.execute(); + return result.getNodes(); + } catch (RepositoryException e) { + throw new AkbException("Unable to list connector", e); + } + } + + @Override + public Node getConnectorByAlias(Node envNode, String aliasName) + throws RepositoryException { + try { + Session session = envNode.getSession(); + QueryManager queryManager = session.getWorkspace() + .getQueryManager(); + QueryObjectModelFactory factory = queryManager.getQOMFactory(); + + Selector source = factory.selector(AkbTypes.AKB_CONNECTOR, + AkbTypes.AKB_CONNECTOR); + Constraint defaultC = factory.descendantNode( + source.getSelectorName(), envNode.getPath()); + + Constraint connType = factory.comparison( + factory.propertyValue(source.getSelectorName(), + AkbNames.AKB_CONNECTOR_ALIAS_NAME), + QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO, factory + .literal(session.getValueFactory().createValue( + aliasName))); + defaultC = factory.and(defaultC, connType); + + QueryObjectModel query; + query = factory.createQuery(source, defaultC, null, null); + QueryResult result = query.execute(); + NodeIterator ni = result.getNodes(); + + if (!ni.hasNext()) + return null; + else { + Node connector = ni.nextNode(); + if (ni.hasNext()) + throw new AkbException("More than one alias with name " + + aliasName + " has been defined for environment " + + envNode); + else + return connector; + } + } catch (RepositoryException e) { + throw new AkbException("Unable to get connector " + aliasName + + " in " + envNode, e); + } + } + + @Override public boolean testConnector(Node connectorNode) { try { if (connectorNode.isNodeType(AkbTypes.AKB_JDBC_CONNECTOR)) { @@ -172,15 +277,22 @@ public class AkbServiceImpl implements AkbService, AkbNames { * Opens a new connection each time. All resources must be cleaned by * caller. */ - public PreparedStatement prepareJdbcQuery(Node node) { + public PreparedStatement prepareJdbcQuery(Node activeEnv, 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); + + if (activeEnv != null){ + String aliasName = connectorNode.getProperty(Property.JCR_TITLE).getString(); + connectorNode = getConnectorByAlias(activeEnv, aliasName); + } + + String sqlQuery = node.getProperty(AKB_QUERY_TEXT).getString(); + String connectorUrl = connectorNode.getProperty( AKB_CONNECTOR_URL).getString(); String connectorUser = connectorNode.getProperty( @@ -210,7 +322,7 @@ public class AkbServiceImpl implements AkbService, AkbNames { } } - public String executeCommand(Node node) { + public String executeCommand(Node activeEnv, Node node) { try { String command = node.getProperty(AkbNames.AKB_COMMAND_TEXT) .getString(); @@ -261,7 +373,7 @@ public class AkbServiceImpl implements AkbService, AkbNames { } - public String retrieveFile(Node node) { + public String retrieveFile(Node activeEnv, Node node) { try { String filePath = node.getProperty(AkbNames.AKB_FILE_PATH) .getString(); diff --git a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/utils/AkbJcrUtils.java b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/utils/AkbJcrUtils.java index 844c3a1cd..d597dc509 100644 --- a/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/utils/AkbJcrUtils.java +++ b/runtime/org.argeo.slc.akb/src/main/java/org/argeo/slc/akb/utils/AkbJcrUtils.java @@ -20,12 +20,14 @@ import javax.jcr.query.RowIterator; import javax.jcr.query.qom.Constraint; import javax.jcr.query.qom.Ordering; import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.QueryObjectModelConstants; import javax.jcr.query.qom.QueryObjectModelFactory; import javax.jcr.query.qom.Selector; import org.argeo.jcr.JcrUtils; import org.argeo.jcr.PropertyDiff; import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.AkbNames; import org.argeo.slc.akb.AkbTypes; /** Some static utils methods that might be factorized in a near future */ @@ -54,19 +56,27 @@ public class AkbJcrUtils { /** * Return defined alias in the current environment given current item type */ + @Deprecated public static List getDefinedAliasForNode(Node itemTemplate) { try { Session session = itemTemplate.getSession(); QueryManager queryManager = session.getWorkspace() .getQueryManager(); QueryObjectModelFactory factory = queryManager.getQOMFactory(); - String nodeType = getAliasTypeForNode(itemTemplate); - Selector source = factory.selector(nodeType, nodeType); + Selector source = factory.selector(AkbTypes.AKB_CONNECTOR_ALIAS, + AkbTypes.AKB_CONNECTOR_ALIAS); String basePath = getCurrentEnvBasePath(itemTemplate); Constraint defaultC = factory.descendantNode( source.getSelectorName(), basePath); + String nodeType = getAliasTypeForNode(itemTemplate); + Constraint connType = factory.comparison(factory.propertyValue( + source.getSelectorName(), AkbNames.AKB_CONNECTOR_TYPE), + QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO, factory + .literal(session.getValueFactory().createValue( + nodeType))); + // Order by default by JCR TITLE // TODO check if node definition has MIX_TITLE mixin // TODO Apparently case insensitive ordering is not implemented in @@ -75,8 +85,9 @@ public class AkbJcrUtils { .ascending(factory.upperCase(factory.propertyValue( source.getSelectorName(), Property.JCR_TITLE))); QueryObjectModel query; - query = factory.createQuery(source, defaultC, - new Ordering[] { order }, null); + query = factory.createQuery(source, + factory.and(defaultC, connType), new Ordering[] { order }, + null); QueryResult result = query.execute(); NodeIterator ni = result.getNodes(); @@ -87,6 +98,33 @@ public class AkbJcrUtils { } } + /** + * Return current template depending on the passed node + */ + public static Node getCurrentTemplate(Node akbNode) { + try { + if (akbNode.getDepth() == 0) + // no base path for root node + return null; + Node parNode = akbNode.getParent(); + + while (parNode != null) + if (akbNode.isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) + return akbNode; + else if (parNode.getDepth() == 0) + // we found not fitting node + return null; + else { + akbNode = parNode; + parNode = parNode.getParent(); + } + return null; + } catch (RepositoryException re) { + throw new AkbException("Unable to find template for node " + + akbNode, re); + } + } + /** * Return the current env base path */ diff --git a/runtime/org.argeo.slc.akb/src/main/resources/org/argeo/slc/akb/akb.cnd b/runtime/org.argeo.slc.akb/src/main/resources/org/argeo/slc/akb/akb.cnd index 474fb4798..a98cde8b6 100644 --- a/runtime/org.argeo.slc.akb/src/main/resources/org/argeo/slc/akb/akb.cnd +++ b/runtime/org.argeo.slc.akb/src/main/resources/org/argeo/slc/akb/akb.cnd @@ -25,28 +25,29 @@ mixin // GENERIC TYPE FOR A CONNECTOR [akb:connector] > nt:unstructured, mix:title - akb:connectorUrl (STRING) +// the name of the corresponding alias. We assume it is unique. +- akb:connectorName (STRING) + // add argeo keyring // ease retrieval and enable adding alias specific properties -[akb:connectorAlias] > akb:connector -// Use akb:connectorUrl property to define default test connector - +[akb:connectorAlias] > nt:unstructured, mix:title ++ defaultTestConnector (akb:connector) +- akb:connectorType (STRING) // HELPER [akb:connectorFolder] > nt:unstructured, mix:title + * (akb:connector, akb:connectorAlias) * - -// Various connector types as mixin -[akb:sshConnector] -mixin +// Various connectors +[akb:sshConnector] > akb:connector -[akb:jdbcConnector] -mixin -[akb:jcrConnector] -mixin +[akb:jdbcConnector] > akb:connector + + +[akb:jcrConnector] > akb:connector