From cce1ca8a555b41f6ca0a77ab549a5e1461f2bb15 Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Sat, 9 Nov 2013 14:37:51 +0000 Subject: [PATCH] Add first draft for Connector Alias and Template environment editors. git-svn-id: https://svn.argeo.org/slc/trunk@6607 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/akb_rcp.properties | 2 +- .../META-INF/spring/commands.xml | 6 + .../META-INF/spring/editors.xml | 1 + plugins/org.argeo.slc.akb.ui/plugin.xml | 9 + .../java/org/argeo/slc/akb/ui/AkbUiUtils.java | 257 ++++++++++++++++++ .../slc/akb/ui/commands/DeleteAkbNodes.java | 71 +++++ .../akb/ui/commands/OpenAkbNodeEditor.java | 23 +- .../akb/ui/composites/MixTitleComposite.java | 96 +++++++ .../akb/ui/editors/AbstractAkbNodeEditor.java | 72 ++++- .../ui/editors/AkbConnectorAliasEditor.java | 185 ++++++++++++- .../akb/ui/editors/AkbEnvTemplateEditor.java | 17 +- .../TemplatesTreeContentProvider.java | 6 +- .../slc/akb/ui/views/AkbDefaultView.java | 2 +- .../akb/ui/views/AkbTemplatesTreeView.java | 154 ++++++++++- .../java/org/argeo/slc/akb/AkbService.java | 10 +- .../main/java/org/argeo/slc/akb/AkbTypes.java | 24 +- .../argeo/slc/akb/core/AkbServiceImpl.java | 19 +- .../main/resources/org/argeo/slc/akb/akb.cnd | 16 +- 18 files changed, 924 insertions(+), 46 deletions(-) create mode 100644 plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/AkbUiUtils.java create mode 100644 plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java create mode 100644 plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/MixTitleComposite.java diff --git a/demo/akb_rcp.properties b/demo/akb_rcp.properties index a45f24a40..3353c86e3 100644 --- a/demo/akb_rcp.properties +++ b/demo/akb_rcp.properties @@ -10,7 +10,7 @@ argeo.osgi.start.2.node=\ org.argeo.node.repo.jackrabbit,\ org.argeo.security.dao.os,\ -org.argeo.security.ui.initialPerspective=org.argeo.slc.akb.ui.akbEnvPerspective +org.argeo.security.ui.initialPerspective=org.argeo.slc.akb.ui.akbTemplatesPerspective eclipse.application=org.argeo.security.ui.rcp.secureUi log4j.configuration=file:../../log4j.properties diff --git a/plugins/org.argeo.slc.akb.ui/META-INF/spring/commands.xml b/plugins/org.argeo.slc.akb.ui/META-INF/spring/commands.xml index 36470a90c..1ed12f648 100644 --- a/plugins/org.argeo.slc.akb.ui/META-INF/spring/commands.xml +++ b/plugins/org.argeo.slc.akb.ui/META-INF/spring/commands.xml @@ -10,4 +10,10 @@ + + + + + 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 25b421588..d9617fe69 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 @@ -10,5 +10,6 @@ + \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/plugin.xml b/plugins/org.argeo.slc.akb.ui/plugin.xml index bdf9dfeee..be04cd2f5 100644 --- a/plugins/org.argeo.slc.akb.ui/plugin.xml +++ b/plugins/org.argeo.slc.akb.ui/plugin.xml @@ -72,6 +72,15 @@ name="The Parent Node JCR ID if needed"> + + + + Text given a Node and a + * property Name + */ + public static String refreshTextWidgetValue(Text text, Node entity, + String propName) { + String tmpStr = AkbJcrUtils.get(entity, propName); + if (AkbJcrUtils.checkNotEmptyString(tmpStr)) + text.setText(tmpStr); + return tmpStr; + } + + /** + * Shortcut to refresh a Text widget given a Node in a form and + * a property Name. Also manages its enable state + */ + public static String refreshFormTextWidget(Text text, Node entity, + String propName) { + String tmpStr = AkbJcrUtils.get(entity, propName); + if (AkbJcrUtils.checkNotEmptyString(tmpStr)) + text.setText(tmpStr); + text.setEnabled(AkbJcrUtils.isNodeCheckedOutByMe(entity)); + return tmpStr; + } + + /** + * Shortcut to refresh a Check box Button widget given a Node + * in a form and a property Name. + */ + public static boolean refreshCheckBoxWidget(Button button, Node entity, + String propName) { + Boolean tmp = null; + try { + if (entity.hasProperty(propName)) { + tmp = entity.getProperty(propName).getBoolean(); + button.setSelection(tmp); + } + } catch (RepositoryException re) { + throw new AkbException("unable get boolean value for property " + + propName); + } + return tmp; + } + + /** + * Shortcut to add a default modify listeners to a Text widget + * that is bound a JCR String Property. Any change in the text is + * immediately stored in the active session, but no save is done. + */ + public static void addTextModifyListener(final Text text, final Node node, + final String propName, final AbstractFormPart part) { + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent event) { + if (setJcrProperty(node, propName, PropertyType.STRING, + text.getText())) + part.markDirty(); + } + }); + } + + /** + * Centralizes management of updating property value. Among other to avoid + * infinite loop when the new value is the same as the ones that is already + * stored in JCR. + * + * @return true if the value as changed + */ + public static boolean setJcrProperty(Node node, String propName, + int propertyType, Object value) { + try { + // int propertyType = getPic().getProperty(propName).getType(); + switch (propertyType) { + case PropertyType.STRING: + if ("".equals((String) value) + && (!node.hasProperty(propName) || node + .hasProperty(propName) + && "".equals(node.getProperty(propName) + .getString()))) + // workaround the fact that the Text widget value cannot be + // set to null + return false; + else if (node.hasProperty(propName) + && node.getProperty(propName).getString() + .equals((String) value)) + // nothing changed yet + return false; + else { + node.setProperty(propName, (String) value); + return true; + } + case PropertyType.BOOLEAN: + if (node.hasProperty(propName) + && node.getProperty(propName).getBoolean() == (Boolean) value) + // nothing changed yet + return false; + else { + node.setProperty(propName, (Boolean) value); + return true; + } + case PropertyType.DATE: + if (node.hasProperty(propName) + && node.getProperty(propName).getDate() + .equals((Calendar) value)) + // nothing changed yet + return false; + else { + node.setProperty(propName, (Calendar) value); + return true; + } + case PropertyType.LONG: + Long lgValue = (Long) value; + + if (lgValue == null) + lgValue = 0L; + + if (node.hasProperty(propName) + && node.getProperty(propName).getLong() == lgValue) + // nothing changed yet + return false; + else { + node.setProperty(propName, lgValue); + return true; + } + + default: + throw new AkbException("Unimplemented save for property type: " + + propertyType + " - property: " + propName); + + } + } catch (RepositoryException re) { + throw new AkbException("Error while setting property" + propName + + " - propertyType: " + propertyType, re); + } + } + + // //////////////////////// + // LAYOUTS AND STYLES + + /** shortcut to set form data while dealing with switching panel */ + public static void setSwitchingFormData(Composite composite) { + FormData fdLabel = new FormData(); + fdLabel.top = new FormAttachment(0, 0); + fdLabel.left = new FormAttachment(0, 0); + fdLabel.right = new FormAttachment(100, 0); + fdLabel.bottom = new FormAttachment(100, 0); + composite.setLayoutData(fdLabel); + } + + public static void setTableDefaultStyle(TableViewer viewer, + int customItemHeight) { + Table table = viewer.getTable(); + table.setLinesVisible(true); + table.setHeaderVisible(false); + } + + /** + * Shortcut to provide a gridlayout with no margin and no spacing (dafault + * are normally 5 px) + */ + public static GridLayout gridLayoutNoBorder() { + return gridLayoutNoBorder(1); + } + + /** + * Shortcut to provide a gridlayout with no margin and no spacing (default + * are normally 5 px) with the given column number (equals width is false). + */ + public static GridLayout gridLayoutNoBorder(int nbOfCol) { + GridLayout gl = new GridLayout(nbOfCol, false); + gl.marginWidth = gl.marginHeight = gl.horizontalSpacing = gl.verticalSpacing = 0; + return gl; + } + + /** Creates a text widget with RowData already set */ + public static Text createRDText(FormToolkit toolkit, Composite parent, + String msg, String toolTip, int width) { + Text text = toolkit.createText(parent, "", SWT.BORDER | SWT.SINGLE + | SWT.LEFT); + text.setMessage(msg); + text.setToolTipText(toolTip); + text.setLayoutData(new RowData(width, SWT.DEFAULT)); + return text; + } + + /** + * Creates a text widget with GridData already set + * + * @param toolkit + * @param parent + * @param msg + * @param toolTip + * @param width + * @param colSpan + * @return + */ + public static Text createGDText(FormToolkit toolkit, Composite parent, + String msg, String toolTip, int width, int colSpan) { + Text text = toolkit.createText(parent, "", SWT.BORDER | SWT.SINGLE + | SWT.LEFT); + text.setMessage(msg); + text.setToolTipText(toolTip); + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false); + gd.widthHint = width; + gd.horizontalSpan = colSpan; + text.setLayoutData(gd); + return text; + } + + /** + * Shortcut to quickly get a FormData object with configured FormAttachment + * + * @param left + * @param top + * @param right + * @param bottom + * @return + */ + public static FormData createformData(int left, int top, int right, + int bottom) { + FormData formData = new FormData(); + formData.left = new FormAttachment(left, 0); + formData.top = new FormAttachment(top, 0); + formData.right = new FormAttachment(right, 0); + formData.bottom = new FormAttachment(bottom, 0); + return formData; + } +} \ 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 new file mode 100644 index 000000000..abc41382d --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/commands/DeleteAkbNodes.java @@ -0,0 +1,71 @@ +package org.argeo.slc.akb.ui.commands; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +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.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Deletes one or more akb nodes also closing the corresponding editors if + * needed + */ +public class DeleteAkbNodes extends AbstractHandler { + public final static String ID = AkbUiPlugin.PLUGIN_ID + ".deleteAkbNodes"; + + /* DEPENDENCY INJECTION */ + private Repository repository; + + public final static String PARAM_NODE_JCR_ID = "param.nodeJcrId"; + + // public final static String PARAM_NODE_TYPE = "param.nodeType"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + // String nodeType = event.getParameter(PARAM_NODE_TYPE); + String nodeJcrId = event.getParameter(PARAM_NODE_JCR_ID); + + Session session = null; + try { + // caches current Page + IWorkbenchPage currentPage = HandlerUtil.getActiveWorkbenchWindow( + event).getActivePage(); + + session = repository.login(); + Node node = null; + + if (nodeJcrId != null) + node = session.getNodeByIdentifier(nodeJcrId); + + // no node has been found or created, return silently + if (node == null) + return null; + + IEditorPart currPart = currentPage + .findEditor(new AkbNodeEditorInput(nodeJcrId)); + if (currPart != null) + currPart.dispose(); + } catch (RepositoryException e) { + throw new AkbException("JCR error while deleting node" + nodeJcrId + + " editor", e); + } finally { + JcrUtils.logoutQuietly(session); + } + return null; + } + + /* DEPENDENCY INJECTION */ + public void setRepository(Repository repository) { + this.repository = repository; + } +} \ 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 46de0c3d1..c77565d42 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 @@ -1,6 +1,7 @@ package org.argeo.slc.akb.ui.commands; import javax.jcr.Node; +import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -74,7 +75,7 @@ public class OpenAkbNodeEditor extends AbstractHandler { String editorId = getEditorForNode(node); - // no editor has been found, return + // no editor has been found, return silently if (editorId == null) return null; @@ -98,17 +99,17 @@ public class OpenAkbNodeEditor extends AbstractHandler { private Node createNewNode(Session session, String nodeType, String parentNodeJcrId) throws RepositoryException { Node node = null; + String name = SingleValue.ask("New name", "Create AKB item"); + + if (name == null) + return null; if (AkbTypes.AKB_ENV_TEMPLATE.equals(nodeType)) { - String name = SingleValue.ask("Template name", - "Please give a name to the template to create"); - if (name != null) - node = akbService.createAkbTemplate( - session.getNodeByIdentifier(parentNodeJcrId), name); - else - return null; + node = akbService.createAkbTemplate( + session.getNodeByIdentifier(parentNodeJcrId), name); } else { Node parentNode = session.getNodeByIdentifier(parentNodeJcrId); - node = parentNode.addNode("new", nodeType); + node = parentNode.addNode(name, nodeType); + node.setProperty(Property.JCR_TITLE, name); } // corresponding node is saved but not checked in, in order to ease // cancel actions. @@ -122,8 +123,8 @@ public class OpenAkbNodeEditor extends AbstractHandler { editorId = AkbConnectorAliasEditor.ID; else if (node.isNodeType(AkbTypes.AKB_ENV_TEMPLATE)) editorId = AkbEnvTemplateEditor.ID; - else - throw new AkbException("Editor is undefined for node " + node); + // else + // throw new AkbException("Editor is undefined for node " + node); return editorId; } diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/MixTitleComposite.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/MixTitleComposite.java new file mode 100644 index 000000000..395648325 --- /dev/null +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/composites/MixTitleComposite.java @@ -0,0 +1,96 @@ +package org.argeo.slc.akb.ui.composites; + +import javax.jcr.Node; +import javax.jcr.Property; + +import org.argeo.slc.akb.ui.AkbUiUtils; +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.Label; +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; + +public class MixTitleComposite extends Composite { + // private final static Log log = + // LogFactory.getLog(MixTitleComposite.class); + + private final Node akbNode; + 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 MixTitleComposite(Composite parent, int style, FormToolkit toolkit, + IManagedForm form, Node akbNode) { + super(parent, style); + this.akbNode = akbNode; + this.toolkit = toolkit; + this.form = form; + populate(); + toolkit.adapt(this); + } + + private void populate() { + // Initialization + Composite parent = this; + + parent.setLayout(new GridLayout(2, false)); + + // first line: connector type and name + toolkit.createLabel(parent, "Name"); + titleTxt = toolkit.createText(parent, "", SWT.BORDER); + GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); + titleTxt.setLayoutData(gd); + + // 2nd line: description + Label lbl = toolkit.createLabel(parent, "Description"); + lbl.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + final Text descTxt = toolkit.createText(parent, "", SWT.BORDER + | SWT.MULTI | SWT.WRAP); + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + descTxt.setLayoutData(gd); + + // Part Management + final AbstractFormPart part = new AbstractFormPart() { + public void refresh() { + super.refresh(); + // update display value + AkbUiUtils.refreshFormTextWidget(titleTxt, akbNode, + Property.JCR_TITLE); + AkbUiUtils.refreshFormTextWidget(descTxt, akbNode, + Property.JCR_DESCRIPTION); + } + }; + // Listeners + AkbUiUtils.addTextModifyListener(titleTxt, akbNode, Property.JCR_TITLE, + part); + AkbUiUtils.addTextModifyListener(descTxt, akbNode, + Property.JCR_DESCRIPTION, part); + form.addPart(part); + } + + @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/editors/AbstractAkbNodeEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AbstractAkbNodeEditor.java index cc7c8ddea..7eb74bb5e 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AbstractAkbNodeEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AbstractAkbNodeEditor.java @@ -8,18 +8,25 @@ import javax.jcr.Session; import org.argeo.jcr.JcrUtils; import org.argeo.slc.akb.AkbException; +import org.argeo.slc.akb.AkbService; import org.argeo.slc.akb.utils.AkbJcrUtils; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.EditorPart; +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.ScrolledForm; /** * Parent Abstract Node editor for AKB. Manage life cycle of the JCR session * that is bound to it. */ -public abstract class AbstractAkbNodeEditor extends EditorPart { +public abstract class AbstractAkbNodeEditor extends FormEditor { // private final static Log log = LogFactory // .getLog(AbstractEntityEditor.class); @@ -27,6 +34,7 @@ public abstract class AbstractAkbNodeEditor extends EditorPart { // changes life cycle private Repository repository; private Session session; + private AkbService akbService; // Business Objects private Node akbNode; @@ -34,7 +42,12 @@ public abstract class AbstractAkbNodeEditor extends EditorPart { // Some constants private final static int SHORT_NAME_LENGHT = 10; - // LIFE CYCLE + // to implement methods + protected abstract String getEditorId(); + + protected abstract void populateMainPage(Composite parent, + IManagedForm managedForm); + public void init(IEditorSite site, IEditorInput input) throws PartInitException { setSite(site); @@ -68,11 +81,50 @@ public abstract class AbstractAkbNodeEditor extends EditorPart { setTitleToolTip("Display and edit " + name); } + /* Pages management */ + @Override + protected void addPages() { + try { + addPage(new ConnectorAliasPage(this, "mainPage", "Main")); + // TODO Add history page + // addPage(new ConnectorAliasPage(this, "mainPage", "Main")); + } catch (PartInitException e) { + throw new AkbException("Unable to initialise pages for editor " + + getEditorId(), e); + } + } + + /** + * Display and edit info + */ + private class ConnectorAliasPage extends FormPage { + + public ConnectorAliasPage(FormEditor editor, String id, String title) { + super(editor, id, title); + } + + protected void createFormContent(IManagedForm managedForm) { + super.createFormContent(managedForm); + ScrolledForm form = managedForm.getForm(); + form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + populateMainPage(form.getBody(), managedForm); + } + } + /* EXPOSES TO CHILDREN CLASSES */ protected Session getSession() { return session; } + protected AkbService getAkbService() { + return akbService; + } + + protected Node getAkbNode() { + return akbNode; + } + + /* LIFE CYCLE MANAGEMENT */ @Override public void dispose() { try { @@ -93,7 +145,15 @@ public abstract class AbstractAkbNodeEditor extends EditorPart { @Override public void doSave(IProgressMonitor monitor) { - throw new AkbException("Implement this"); + try { + if (getSession().hasPendingChanges()) + JcrUtils.updateLastModified(getAkbNode()); + getSession().save(); + updatePartNameAndToolTip(); + this.firePropertyChange(PROP_DIRTY); + } catch (Exception e) { + throw new AkbException("Error getting session status.", e); + } } @Override @@ -118,4 +178,8 @@ public abstract class AbstractAkbNodeEditor extends EditorPart { public void setRepository(Repository repository) { this.repository = repository; } + + public void setAkbService(AkbService akbService) { + this.akbService = akbService; + } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbConnectorAliasEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbConnectorAliasEditor.java index 2ff704c45..a3b776c81 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbConnectorAliasEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbConnectorAliasEditor.java @@ -1,18 +1,201 @@ package org.argeo.slc.akb.ui.editors; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +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; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; /** * Display and edit a connector Alias */ public class AkbConnectorAliasEditor extends AbstractAkbNodeEditor { + // private final static Log log = LogFactory + // .getLog(AkbConnectorAliasEditor.class); public final static String ID = AkbUiPlugin.PLUGIN_ID + ".akbConnectorAliasEditor"; + 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; + /* CONTENT CREATION */ @Override - public void createPartControl(Composite parent) { + public void populateMainPage(Composite parent, IManagedForm managedForm) { + parent.setLayout(AkbUiUtils.gridLayoutNoBorder()); + this.managedForm = managedForm; + + // First line main info + Composite firstLine = getToolkit() + .createComposite(parent, SWT.NO_FOCUS); + firstLine.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + createConnectorAliasInfoCmp(firstLine); + + // Second line define defaut connector and test abilities + Composite secondLine = getToolkit().createComposite(parent, + SWT.NO_FOCUS); + secondLine.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + createDefaultTestConnectorCmp(secondLine); + + } + + 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); + + getToolkit().createLabel(parent, "Name"); + final Text titleTxt = getToolkit().createText(parent, "", SWT.BORDER); + GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); + titleTxt.setLayoutData(gd); + + // 2nd line: description + getToolkit().createLabel(parent, "Short Description"); + final Text descTxt = getToolkit().createText(parent, "", SWT.BORDER); + gd = new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1); + descTxt.setLayoutData(gd); + + // Part Management + final AbstractFormPart part = new AbstractFormPart() { + public void refresh() { + super.refresh(); + // update display value + AkbUiUtils.refreshFormTextWidget(titleTxt, getAkbNode(), + Property.JCR_TITLE); + AkbUiUtils.refreshFormTextWidget(descTxt, getAkbNode(), + Property.JCR_DESCRIPTION); + } + }; + // Listeners + AkbUiUtils.addTextModifyListener(titleTxt, getAkbNode(), + Property.JCR_TITLE, part); + 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 = -1; + for (int i = 0; i < connectorTypes.length; i++) { + if (getAkbNode().isNodeType(connectorTypes[i])) { + oldIndex = i; + break; + } + } + 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 void createDefaultTestConnectorCmp(Composite parent) { + String groupTitle = "Default test instance"; + parent.setLayout(new GridLayout()); + Group group = new Group(parent, SWT.NONE); + group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + getToolkit().adapt(group, false, false); + + group.setText(groupTitle); + group.setLayout(AkbUiUtils.gridLayoutNoBorder()); + // 1st line: the URL + + Composite firstLine = getToolkit().createComposite(group); + firstLine.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + firstLine.setLayout(new GridLayout(3, false)); + + getToolkit().createLabel(firstLine, "URL"); + final Text urlTxt = getToolkit().createText(firstLine, "", SWT.BORDER); + urlTxt.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, + // false)); + + // Part Management + final AbstractFormPart part = new AbstractFormPart() { + public void refresh() { + super.refresh(); + // update display value + AkbUiUtils.refreshFormTextWidget(urlTxt, getAkbNode(), + AkbNames.AKB_CONNECTOR_URL); + } + }; + // Listeners + AkbUiUtils.addTextModifyListener(urlTxt, getAkbNode(), + AkbNames.AKB_CONNECTOR_URL, part); + + testBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean testSuccesfull = getAkbService().testConnector( + getAkbNode()); + + String name = AkbJcrUtils.get(getAkbNode(), Property.JCR_TITLE); + String url = AkbJcrUtils.get(getAkbNode(), + AkbNames.AKB_CONNECTOR_URL); + + String msg = "to " + name + " (" + url + ")"; + if (testSuccesfull) + MessageDialog.openInformation(getSite().getShell(), + "Test successful", "Successfully connected " + msg); + else + MessageDialog.openError(getSite().getShell(), + "Test failure", "Unable to connect" + msg); + } + }); + + managedForm.addPart(part); + + } + + @Override + protected String getEditorId() { + return ID; } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbEnvTemplateEditor.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbEnvTemplateEditor.java index 8a16202fe..49f443a97 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbEnvTemplateEditor.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/editors/AkbEnvTemplateEditor.java @@ -1,7 +1,12 @@ package org.argeo.slc.akb.ui.editors; import org.argeo.slc.akb.ui.AkbUiPlugin; +import org.argeo.slc.akb.ui.AkbUiUtils; +import org.argeo.slc.akb.ui.composites.MixTitleComposite; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.forms.IManagedForm; /** * Display and edit a connector Alias @@ -13,6 +18,16 @@ public class AkbEnvTemplateEditor extends AbstractAkbNodeEditor { /* CONTENT CREATION */ @Override - public void createPartControl(Composite parent) { + public void populateMainPage(Composite parent, IManagedForm managedForm) { + parent.setLayout(AkbUiUtils.gridLayoutNoBorder()); + // 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)); + } + + @Override + protected String getEditorId() { + return ID; } } \ No newline at end of file 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 33571446f..1f39f33d8 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 @@ -42,7 +42,11 @@ public class TemplatesTreeContentProvider implements ITreeContentProvider { public Object getParent(Object child) { try { - return ((Node) child).getParent(); + Node node = (Node) child; + if (node.getDepth() == 0) + return null; + else + return node.getParent(); } catch (RepositoryException e) { throw new AkbException("Error while getting parent node", e); } diff --git a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbDefaultView.java b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbDefaultView.java index 44c419738..ac3e5a49d 100644 --- a/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbDefaultView.java +++ b/plugins/org.argeo.slc.akb.ui/src/main/java/org/argeo/slc/akb/ui/views/AkbDefaultView.java @@ -171,4 +171,4 @@ public class AkbDefaultView extends ViewPart { // + "session for view " + ID, e); // } } - } \ No newline at end of file +} \ No newline at end of file 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 9ab230520..004e151c5 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 @@ -25,19 +25,26 @@ import javax.jcr.NodeIterator; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventListener; +import javax.jcr.observation.ObservationManager; +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; 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.AkbTypes; import org.argeo.slc.akb.ui.AkbUiPlugin; +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.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; @@ -45,9 +52,13 @@ import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; 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 { @@ -66,6 +77,12 @@ public class AkbTemplatesTreeView extends ViewPart { // Usefull business objects private Node templatesParentNode; + // Observer + private EventListener allResultsObserver = null; + private final static String[] observedNodeTypesUnderAllResults = { + AkbTypes.AKB_ENV_TEMPLATE, AkbTypes.AKB_CONNECTOR_ALIAS, + AkbTypes.AKB_ITEM, AkbTypes.AKB_ITEM_FOLDER }; + // private EventListener myResultsObserver = null; // private EventListener allResultsObserver = null; // @@ -200,12 +217,50 @@ public class AkbTemplatesTreeView extends ViewPart { getSite().registerContextMenu(menuManager, viewer); + // Initialize observer + try { + ObservationManager observationManager = session.getWorkspace() + .getObservationManager(); + + allResultsObserver = new AllResultsObserver(viewer.getTree() + .getDisplay()); + + // observe tree changes under All results + observationManager.addEventListener(allResultsObserver, + Event.NODE_ADDED | Event.NODE_REMOVED, + templatesParentNode.getPath(), true, null, + observedNodeTypesUnderAllResults, 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 { + resultTreeViewer.setInput(initializeResultTree()); + // if (lastSelectedSourceElementParent != null) + // refresh(lastSelectedSourceElementParent); + } + } + // Detailed property viewer // protected TableViewer createPropertiesViewer(Composite parent) { // } @@ -243,22 +298,111 @@ public class AkbTemplatesTreeView extends ViewPart { IWorkbenchWindow window = AkbUiPlugin.getDefault().getWorkbench() .getActiveWorkbenchWindow(); try { + + // Build conditions + Node selected = (Node) ((IStructuredSelection) resultTreeViewer + .getSelection()).getFirstElement(); + + boolean hasSelection = selected != null; + 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; + + // Add Connector Alias Map params = new HashMap(); + if (hasSelection) + 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 + 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); + + // Add Item Folder + params = new HashMap(); + if (hasSelection) + params.put(OpenAkbNodeEditor.PARAM_PARENT_NODE_JCR_ID, + selected.getIdentifier()); + params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, + AkbTypes.AKB_ITEM_FOLDER); + refreshParameterizedCommand(menuManager, window, + "cmd.addItemFolder", OpenAkbNodeEditor.ID, + "Add item folder", null, isParentItemsFolder, 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); + + // create template + params = new HashMap(); params.put(OpenAkbNodeEditor.PARAM_PARENT_NODE_JCR_ID, templatesParentNode.getIdentifier()); params.put(OpenAkbNodeEditor.PARAM_NODE_TYPE, AkbTypes.AKB_ENV_TEMPLATE); - - // Effective Refresh - CommandUtils.refreshParametrizedCommand(menuManager, window, - OpenAkbNodeEditor.ID, "Create new template...", null, true, - params); + refreshParameterizedCommand(menuManager, window, + "cmd.createTemplate", OpenAkbNodeEditor.ID, + "Create new template...", null, true, params); } catch (RepositoryException re) { throw new AkbException("Error while refreshing context menu", re); } } + /** + * 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 + */ + private 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); + CommandContributionItemParameter contributionItemParameter = new CommandContributionItemParameter( + locator, itemId, cmdId, SWT.PUSH); + + if (showCommand) { + // Set Params + contributionItemParameter.label = label; + contributionItemParameter.icon = icon; + + if (params != null) + contributionItemParameter.parameters = params; + + CommandContributionItem cci = new CommandContributionItem( + contributionItemParameter); + menuManager.add(cci); + } + } + /* INNER CLASSES */ class ViewDoubleClickListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent evt) { 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 7f5348a2a..1f39ff832 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 @@ -7,5 +7,13 @@ import javax.jcr.RepositoryException; public interface AkbService { /** Creates a preconfigured AKB Template */ - public Node createAkbTemplate(Node parent, String name) throws RepositoryException; + public Node createAkbTemplate(Node parent, String name) + 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 + */ + public boolean testConnector(Node connector); } 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 82407f1ce..349e419ee 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 @@ -1,31 +1,33 @@ package org.argeo.slc.akb; -/** Maps AKB specific JCR node types with java constants */ +/** Maps AKB specific JCR node types with java constants */ public interface AkbTypes { public final static String ARGEO_NOTE = "argeo:note"; - // Env and templates + // Env and templates public final static String AKB_ENV_TEMPLATE = "akb:envTemplate"; - public final static String AKB_ENV= "akb:env"; + public final static String AKB_ENV = "akb:env"; // Connectors - public final static String AKB_CONNECTOR = "akb:connector"; - public final static String AKB_CONNECTOR_ALIAS = "akb:connectorAlias"; + + 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"; // Various connector mixin types - public final static String AKB_SSH_CONNECTOR = "akb:sshConnector"; - public final static String AKB_JDBC_CONNECTOR = "akb:jdbcConnector"; - - // Item tree + public final static String AKB_SSH_CONNECTOR = "akb:sshConnector"; + public final static String AKB_JDBC_CONNECTOR = "akb:jdbcConnector"; + public final static String AKB_JCR_CONNECTOR = "akb:jcrConnector"; + + // Item tree public final static String AKB_ITEM_FOLDER = "akb:itemsFolder"; public final static String AKB_ITEM = "akb:item"; - + // Various items types public final static String AKB_SSH_FILE = "akb:sshFile"; public final static String AKB_SSH_COMMAND = "akb:sshCommand"; public final static String AKB_JDBC_QUERY = "akb:jdbcQuery"; public final static String AKB_NOTE = "akb:note"; - } \ No newline at end of file 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 b228b0a75..e819bbfa8 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 @@ -8,7 +8,6 @@ import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -76,19 +75,25 @@ public class AkbServiceImpl implements AkbService, AkbNames { Node newTemplate = parentNode.addNode(name, AkbTypes.AKB_ENV_TEMPLATE); newTemplate.setProperty(Property.JCR_TITLE, name); - Node connectorParent = newTemplate.addNode(connectorParentName, - NodeType.NT_UNSTRUCTURED); - connectorParent.addMixin(NodeType.MIX_TITLE); + Node connectorParent = newTemplate.addNode( + AkbTypes.AKB_CONNECTOR_FOLDER, AkbTypes.AKB_CONNECTOR_FOLDER); connectorParent.setProperty(Property.JCR_TITLE, connectorParentName); - Node itemsParent = newTemplate.addNode(itemsParentName, - NodeType.NT_UNSTRUCTURED); - itemsParent.addMixin(NodeType.MIX_TITLE); + Node itemsParent = newTemplate.addNode(AkbTypes.AKB_ITEM_FOLDER, + AkbTypes.AKB_ITEM_FOLDER); itemsParent.setProperty(Property.JCR_TITLE, itemsParentName); return newTemplate; } + // /////////////////////////////////////// + // / CONNECTORS + + public boolean testConnector(Node connector) { + // TODO Implement this. + return false; + } + // /** Expose injected repository */ // public Repository getRepository() { // return repository; 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 0e451b343..ad1067348 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 @@ -27,7 +27,15 @@ mixin - akb:connectorUrl (STRING) // add argeo keyring -[akb:connectorAlias] > nt:unstructured, mix:title +// ease retrieval and enable adding alias specific properties +[akb:connectorAlias] > akb:connector +// Use akb:connectorUrl property to define default test connector + + +// HELPER +[akb:connectorFolder] > nt:unstructured, mix:title ++ * (akb:connector, akb:connectorAlias) * + // Various connector types as mixin @@ -37,6 +45,9 @@ mixin [akb:jdbcConnector] mixin +[akb:jcrConnector] +mixin + // @@ -47,8 +58,9 @@ mixin // // GENERIC ITEM FOLDER // -[akb:itemsFolder] > nt:unstructured +[akb:itemsFolder] > nt:unstructured, mix:title + * (akb:item) * ++ * (akb:itemsFolder) * // // SSH FILE -- 2.39.5