Work on the modular distribution - generate binaries, work on layout.
authorBruno Sinou <bsinou@argeo.org>
Tue, 11 Mar 2014 20:05:52 +0000 (20:05 +0000)
committerBruno Sinou <bsinou@argeo.org>
Tue, 11 Mar 2014 20:05:52 +0000 (20:05 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@6892 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

16 files changed:
plugins/org.argeo.slc.client.ui.dist/icons/clear.gif [new file with mode: 0644]
plugins/org.argeo.slc.client.ui.dist/plugin.xml
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenGenerateBinariesWizard.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionEditor.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java [deleted file]
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java

diff --git a/plugins/org.argeo.slc.client.ui.dist/icons/clear.gif b/plugins/org.argeo.slc.client.ui.dist/icons/clear.gif
new file mode 100644 (file)
index 0000000..cbb71be
Binary files /dev/null and b/plugins/org.argeo.slc.client.ui.dist/icons/clear.gif differ
index 59bda30afef995fadb3b83f46200894cdee083d4..58623ebf51220747e6c75d436a2886328303ae47 100644 (file)
             name="Mark as relevant category">
        </command>
        
+       <command
+            defaultHandler="org.argeo.slc.client.ui.dist.commands.OpenGenerateBinariesWizard"
+            id="org.argeo.slc.client.ui.dist.openGenerateBinariesWizard"
+            name="Generate Binaries...">
+       </command>
+       
        <command
             id="org.argeo.slc.client.ui.dist.normalizeWorkspace"
             defaultHandler="org.argeo.eclipse.spring.SpringCommandHandler"
index e54b93434c793b6677bbf7f137776a668ac421c9..097f7350b541bfec2832d879ea8bab7e8ab9b322 100644 (file)
@@ -57,18 +57,19 @@ public class DistImages {
        public final static Image IMG_DISTGRP_READONLY = DistPlugin
                        .getImageDescriptor("icons/distGrpReadOnly.gif").createImage();
 
-       public final static Image IMG_MODULAR_DIST_BASE = DistPlugin.getImageDescriptor(
-                       "icons/packages.gif").createImage();
-       public final static Image IMG_MODULAR_DIST_VERSION = DistPlugin.getImageDescriptor(
-                       "icons/packages.gif").createImage();
+       public final static Image IMG_MODULAR_DIST_BASE = DistPlugin
+                       .getImageDescriptor("icons/packages.gif").createImage();
+       public final static Image IMG_MODULAR_DIST_VERSION = DistPlugin
+                       .getImageDescriptor("icons/packages.gif").createImage();
 
        public final static Image IMG_GROUP_BASE = DistPlugin.getImageDescriptor(
                        "icons/packages.gif").createImage();
 
-
-       /* CHECK BOXES */
+       /* Various */
        public final static Image CHECKED = DistPlugin.getImageDescriptor(
                        "icons/checked.gif").createImage();
        public final static Image UNCHECKED = DistPlugin.getImageDescriptor(
                        "icons/unchecked.gif").createImage();
+       public final static Image IMG_CLEAR = DistPlugin.getImageDescriptor(
+                       "icons/clear.gif").createImage();
 }
diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenGenerateBinariesWizard.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenGenerateBinariesWizard.java
new file mode 100644 (file)
index 0000000..d9f72d1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.client.ui.dist.commands;
+
+import java.util.Iterator;
+
+import org.argeo.slc.client.ui.dist.DistPlugin;
+import org.argeo.slc.client.ui.dist.model.ModularDistBaseElem;
+import org.argeo.slc.client.ui.dist.utils.CommandHelpers;
+import org.argeo.slc.client.ui.dist.wizards.GenerateBinariesWizard;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Open a {@code GenerateBinariesWizard} wizard for the selected node
+ */
+public class OpenGenerateBinariesWizard extends AbstractHandler {
+       // private static final Log log = LogFactory.getLog(DeleteWorkspace.class);
+
+       public final static String ID = DistPlugin.ID
+                       + ".openGenerateBinariesWizard";
+       public final static String DEFAULT_LABEL = "Generate Aether Index";
+       public final static ImageDescriptor DEFAULT_ICON = null;
+
+       public Object execute(ExecutionEvent event) throws ExecutionException {
+               IWorkbenchPart activePart = DistPlugin.getDefault().getWorkbench()
+                               .getActiveWorkbenchWindow().getActivePage().getActivePart();
+
+               if (activePart instanceof IViewPart) {
+                       ISelection selector = ((IViewPart) activePart).getViewSite()
+                                       .getSelectionProvider().getSelection();
+                       if (selector != null && selector instanceof IStructuredSelection) {
+                               Iterator<?> it = ((IStructuredSelection) selector).iterator();
+                               Object element = it.next();
+                               if (element instanceof ModularDistBaseElem) {
+                                       ModularDistBaseElem elem = (ModularDistBaseElem) element;
+
+                                       GenerateBinariesWizard wizard = new GenerateBinariesWizard(
+                                                       elem.getCategoryBase());
+                                       WizardDialog dialog = new WizardDialog(
+                                                       HandlerUtil.getActiveShell(event), wizard);
+                                       int result = dialog.open();
+                                       if (result == Dialog.OK)
+                                               CommandHelpers.callCommand(RefreshDistributionsView.ID);
+                               }
+
+                       }
+               }
+               return null;
+       }
+}
\ No newline at end of file
index d2d0773deb2e8b4a5d75732686f5cd4923535e9d..e34c2dbf51ea51da0b38b6a24816446618406668 100644 (file)
@@ -90,7 +90,7 @@ public class BundleDetailsPage extends FormPage implements SlcNames, SlcTypes {
                        form.setText(currBundle.hasProperty(DistConstants.SLC_BUNDLE_NAME) ? currBundle
                                        .getProperty(DistConstants.SLC_BUNDLE_NAME).getString()
                                        : "");
-                       form.setMessage(" test", IMessageProvider.NONE);
+                       form.setMessage(" ", IMessageProvider.NONE);
                        Composite body = form.getBody();
                        GridLayout layout = new GridLayout(1, false);
                        layout.marginWidth = 5;
index 75263b53a6e0709c09c2c69bf8ed5d67783db648..f80c5e92861fbb1aeff7b88aeb6733c5b0c29b5e 100644 (file)
@@ -40,7 +40,7 @@ public class ModularDistVersionEditor extends ArtifactVersionEditor {
        @Override
        protected void addPages() {
                try {
-                       addPage(new ModuleListPage(this, "Modules ", getArtifact()));
+                       addPage(new ModularDistVersionOverviewPage(this, "Modules ", getArtifact()));
                        addPage(new RunInOsgiPage(this, "Run as OSGi ", getArtifact()));
                        super.addPages();
                } catch (PartInitException e) {
diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java
new file mode 100644 (file)
index 0000000..66df95c
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.client.ui.dist.editors;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PropertyType;
+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.DynamicOperand;
+import javax.jcr.query.qom.QueryObjectModel;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.StaticOperand;
+
+import org.argeo.ArgeoException;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.utils.CommandUtils;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.client.ui.dist.DistConstants;
+import org.argeo.slc.client.ui.dist.DistImages;
+import org.argeo.slc.client.ui.dist.DistPlugin;
+import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts;
+import org.argeo.slc.client.ui.dist.utils.AbstractHyperlinkListener;
+import org.argeo.slc.client.ui.dist.utils.NodeViewerComparator;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.RepoConstants;
+import org.argeo.slc.repo.RepoUtils;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.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.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+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.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+/**
+ * Show all modules contained in a given modular distribution as filter-able
+ * table
+ */
+public class ModularDistVersionOverviewPage extends FormPage implements
+               SlcNames {
+
+       final static String PAGE_ID = "ModularDistVersionOverviewPage";
+
+       // Business Objects
+       private Node modularDistribution;
+       // private Node modularDistributionBase;
+
+       // This page widgets
+       private NodeViewerComparator comparator;
+       private TableViewer viewer;
+       private FormToolkit tk;
+       private Text filterTxt;
+       private final static String FILTER_HELP_MSG = "Enter filter criterion separated by a space";
+
+       public ModularDistVersionOverviewPage(FormEditor formEditor, String title,
+                       Node modularDistribution) {
+               super(formEditor, PAGE_ID, title);
+               this.modularDistribution = modularDistribution;
+       }
+
+       @Override
+       protected void createFormContent(IManagedForm managedForm) {
+               // General settings for this page
+               ScrolledForm form = managedForm.getForm();
+               tk = managedForm.getToolkit();
+               Composite body = form.getBody();
+
+               GridLayout layout = new GridLayout(1, false);
+               layout.marginWidth = 5;
+               layout.marginRight = 15;
+               layout.verticalSpacing = 0;
+               body.setLayout(layout);
+               try {
+                       form.setText(modularDistribution
+                                       .hasProperty(DistConstants.SLC_BUNDLE_NAME) ? modularDistribution
+                                       .getProperty(DistConstants.SLC_BUNDLE_NAME).getString()
+                                       : "");
+                       form.setMessage(
+                                       modularDistribution
+                                                       .hasProperty(SlcNames.SLC_BUNDLE_DESCRIPTION) ? modularDistribution
+                                                       .getProperty(SlcNames.SLC_BUNDLE_DESCRIPTION)
+                                                       .getString() : "", IMessageProvider.NONE);
+               } catch (RepositoryException re) {
+                       throw new SlcException("Unable to get bundle name for node "
+                                       + modularDistribution, re);
+               }
+
+               // Main layout
+               Composite header = tk.createComposite(body);
+               header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+               populateHeaderPart(header);
+
+               Composite moduleTablePart = tk.createComposite(body);
+               moduleTablePart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                               true));
+               populateModuleTablePart(moduleTablePart);
+       }
+
+       private void populateHeaderPart(Composite parent) {
+               GridLayout layout = new GridLayout(6, false);
+               // layout.marginWidth = layout.horizontalSpacing = layout.marginHeight =
+               // 0;
+               layout.horizontalSpacing = 10;
+               parent.setLayout(layout);
+               try {
+                       // 1st Line: Category, name version
+                       createLT(
+                                       parent,
+                                       "Category",
+                                       modularDistribution.hasProperty(SlcNames.SLC_GROUP_ID) ? modularDistribution
+                                                       .getProperty(SlcNames.SLC_GROUP_ID).getString()
+                                                       : "");
+                       createLT(
+                                       parent,
+                                       "Name",
+                                       modularDistribution.hasProperty(SlcNames.SLC_SYMBOLIC_NAME) ? modularDistribution
+                                                       .getProperty(SlcNames.SLC_SYMBOLIC_NAME)
+                                                       .getString() : "");
+                       createLT(
+                                       parent,
+                                       "Version",
+                                       modularDistribution
+                                                       .hasProperty(SlcNames.SLC_BUNDLE_VERSION) ? modularDistribution
+                                                       .getProperty(SlcNames.SLC_BUNDLE_VERSION)
+                                                       .getString() : "");
+
+                       // 2nd Line: Vendor, licence, sources
+                       createLT(
+                                       parent,
+                                       "Vendor",
+                                       modularDistribution
+                                                       .hasProperty(DistConstants.SLC_BUNDLE_VENDOR) ? modularDistribution
+                                                       .getProperty(DistConstants.SLC_BUNDLE_VENDOR)
+                                                       .getString() : "");
+
+                       createHyperlink(parent, "Licence", DistConstants.SLC_BUNDLE_LICENCE);
+                       addSourceSourcesLink(parent);
+               } catch (RepositoryException re) {
+                       throw new SlcException("Unable to get bundle name for node "
+                                       + modularDistribution, re);
+               }
+
+       }
+
+       private Text createLT(Composite parent, String labelValue, String textValue) {
+               Label label = tk.createLabel(parent, labelValue, SWT.RIGHT);
+               // label.setFont(EclipseUiUtils.getBoldFont(parent));
+               label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+               // Add a trailing space to workaround a display glitch in RAP 1.3
+               Text text = tk.createText(parent, textValue + " ", SWT.LEFT);
+               text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+               text.setEditable(false);
+               return text;
+       }
+
+       private void createHyperlink(Composite parent, String label,
+                       String jcrPropName) throws RepositoryException {
+               tk.createLabel(parent, label, SWT.NONE);
+               if (modularDistribution.hasProperty(jcrPropName)) {
+                       final Hyperlink link = tk.createHyperlink(parent,
+                                       modularDistribution.getProperty(jcrPropName).getString(),
+                                       SWT.NONE);
+                       link.addHyperlinkListener(new AbstractHyperlinkListener() {
+                               @Override
+                               public void linkActivated(HyperlinkEvent e) {
+                                       try {
+                                               IWorkbenchBrowserSupport browserSupport = PlatformUI
+                                                               .getWorkbench().getBrowserSupport();
+                                               IWebBrowser browser = browserSupport
+                                                               .createBrowser(
+                                                                               IWorkbenchBrowserSupport.LOCATION_BAR
+                                                                                               | IWorkbenchBrowserSupport.NAVIGATION_BAR,
+                                                                               "SLC Distribution browser",
+                                                                               "SLC Distribution browser",
+                                                                               "A tool tip");
+                                               browser.openURL(new URL(link.getText()));
+                                       } catch (Exception ex) {
+                                               throw new SlcException("error opening browser", ex); //$NON-NLS-1$
+                                       }
+                               }
+                       });
+               } else
+                       tk.createLabel(parent, "", SWT.NONE);
+       }
+
+       // helper to check if sources are available
+       private void addSourceSourcesLink(Composite parent) {
+               try {
+                       String srcPath = RepoUtils.relatedPdeSourcePath(
+                                       RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH,
+                                       modularDistribution);
+                       if (!modularDistribution.getSession().nodeExists(srcPath)) {
+                               createLT(parent, "Sources", "N/A");
+                       } else {
+                               Node sourcesNode = modularDistribution.getSession().getNode(
+                                               srcPath);
+
+                               Label label = tk.createLabel(parent, "Sources", SWT.RIGHT);
+                               label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
+                                               false));
+
+                               final Hyperlink link = tk.createHyperlink(parent, sourcesNode
+                                               .getProperty(SlcNames.SLC_SYMBOLIC_NAME).getString(),
+                                               SWT.NONE);
+                               link.addHyperlinkListener(new AbstractHyperlinkListener() {
+                                       @Override
+                                       public void linkActivated(HyperlinkEvent e) {
+                                               try {
+                                                       System.out.println("CLICK on Sources link");
+                                               } catch (Exception ex) {
+                                                       throw new SlcException("error opening browser", ex); //$NON-NLS-1$
+                                               }
+                                       }
+                               });
+
+                       }
+               } catch (RepositoryException e) {
+                       throw new SlcException("Unable to configure sources link for "
+                                       + modularDistribution, e);
+               }
+       }
+
+       private void populateModuleTablePart(Composite parent) {
+               GridLayout layout = new GridLayout(1, false);
+               layout.marginWidth = layout.horizontalSpacing = 0;
+               layout.verticalSpacing = 5;
+               layout.marginTop = 15;
+               parent.setLayout(layout);
+               // A sub title
+               Label label = tk.createLabel(parent,
+                               "Modules included in the current distribution", SWT.NONE);
+               label.setFont(EclipseUiUtils.getBoldFont(parent));
+
+               // Add the filter section
+               Composite filterPart = tk.createComposite(parent);
+               filterPart.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+               createFilterPart(filterPart);
+
+               // Add the table
+               Composite tablePart = tk.createComposite(parent);
+               tablePart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               createTableViewer(tablePart);
+               // populate it on first pass.
+               refresh();
+
+       }
+
+       private void createFilterPart(Composite parent) {
+               GridLayout layout = new GridLayout(2, false);
+               layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0;
+               layout.horizontalSpacing = 5;
+               parent.setLayout(layout);
+
+               // Text Area to filter
+               filterTxt = tk.createText(parent, "", SWT.BORDER | SWT.SINGLE
+                               | SWT.SEARCH | SWT.CANCEL);
+               filterTxt.setMessage(FILTER_HELP_MSG);
+               filterTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               filterTxt.addModifyListener(new ModifyListener() {
+                       public void modifyText(ModifyEvent event) {
+                               refresh();
+                       }
+               });
+
+               Button resetBtn = tk.createButton(parent, null, SWT.PUSH);
+               resetBtn.setImage(DistImages.IMG_CLEAR);
+               resetBtn.addSelectionListener(new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               filterTxt.setText("");
+                               filterTxt.setMessage(FILTER_HELP_MSG);
+                       }
+               });
+       }
+
+       private void createTableViewer(Composite parent) {
+               parent.setLayout(new FillLayout());
+               // helpers to enable sorting by column
+               List<String> propertiesList = new ArrayList<String>();
+               List<Integer> propertyTypesList = new ArrayList<Integer>();
+
+               // Define the TableViewer
+               viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
+                               | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
+
+               // Name
+               TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
+               col.getColumn().setWidth(220);
+               col.getColumn().setText("Category");
+               col.setLabelProvider(new ColumnLabelProvider() {
+                       @Override
+                       public String getText(Object element) {
+                               return JcrUtils.get((Node) element, SlcNames.SLC_CATEGORY);
+                       }
+               });
+               col.getColumn().addSelectionListener(getSelectionAdapter(0));
+               propertiesList.add(SlcNames.SLC_CATEGORY);
+               propertyTypesList.add(PropertyType.STRING);
+
+               // Symbolic name
+               col = new TableViewerColumn(viewer, SWT.NONE);
+               col.getColumn().setWidth(220);
+               col.getColumn().setText("Name");
+               col.setLabelProvider(new ColumnLabelProvider() {
+                       @Override
+                       public String getText(Object element) {
+                               return JcrUtils.get((Node) element, SLC_NAME);
+                       }
+               });
+               col.getColumn().addSelectionListener(getSelectionAdapter(1));
+               propertiesList.add(SLC_NAME);
+               propertyTypesList.add(PropertyType.STRING);
+
+               // Version
+               col = new TableViewerColumn(viewer, SWT.NONE);
+               col.getColumn().setWidth(160);
+               col.getColumn().setText("Version");
+               col.setLabelProvider(new ColumnLabelProvider() {
+                       @Override
+                       public String getText(Object element) {
+                               return JcrUtils.get((Node) element, SLC_VERSION);
+                       }
+               });
+               col.getColumn().addSelectionListener(getSelectionAdapter(2));
+               propertiesList.add(SLC_VERSION);
+               propertyTypesList.add(PropertyType.STRING);
+
+               final Table table = viewer.getTable();
+               table.setHeaderVisible(true);
+               table.setLinesVisible(true);
+
+               viewer.setContentProvider(new DistributionsContentProvider());
+               getSite().setSelectionProvider(viewer);
+
+               comparator = new NodeViewerComparator(2,
+                               NodeViewerComparator.ASCENDING, propertiesList,
+                               propertyTypesList);
+               viewer.setComparator(comparator);
+
+               // Context Menu
+               MenuManager menuManager = new MenuManager();
+               Menu menu = menuManager.createContextMenu(viewer.getTable());
+               menuManager.addMenuListener(new IMenuListener() {
+                       public void menuAboutToShow(IMenuManager manager) {
+                               contextMenuAboutToShow(manager);
+                       }
+               });
+               viewer.getTable().setMenu(menu);
+               getSite().registerContextMenu(menuManager, viewer);
+
+               // Double click
+               viewer.addDoubleClickListener(new DoubleClickListener());
+       }
+
+       private void refresh() {
+               final List<Node> result = JcrUtils
+                               .nodeIteratorToList(listBundleArtifacts());
+               viewer.setInput(result);
+       }
+
+       /** Build repository request */
+       private NodeIterator listBundleArtifacts() {
+               try {
+                       Session session = modularDistribution.getSession();
+                       QueryManager queryManager = session.getWorkspace()
+                                       .getQueryManager();
+                       QueryObjectModelFactory factory = queryManager.getQOMFactory();
+
+                       Selector source = factory.selector(SlcTypes.SLC_MODULE_COORDINATES,
+                                       SlcTypes.SLC_MODULE_COORDINATES);
+
+                       // Create a dynamic operand for each property on which we want to
+                       // filter
+                       DynamicOperand catDO = factory.propertyValue(
+                                       source.getSelectorName(), SlcNames.SLC_CATEGORY);
+                       DynamicOperand nameDO = factory.propertyValue(
+                                       source.getSelectorName(), SlcNames.SLC_NAME);
+                       DynamicOperand versionDO = factory.propertyValue(
+                                       source.getSelectorName(), SlcNames.SLC_VERSION);
+
+                       String path = modularDistribution.getPath() + "/"
+                                       + SlcNames.SLC_MODULES;
+
+                       // Default Constraint: correct children
+                       Constraint defaultC = factory.descendantNode(
+                                       source.getSelectorName(), path);
+
+                       String filter = filterTxt.getText();
+
+                       // Build constraints based the textArea content
+                       if (filter != null && !"".equals(filter.trim())) {
+                               // Parse the String
+                               String[] strs = filter.trim().split(" ");
+                               for (String token : strs) {
+                                       token = token.replace('*', '%');
+                                       StaticOperand so = factory.literal(session
+                                                       .getValueFactory().createValue("%" + token + "%"));
+
+                                       Constraint currC = factory.comparison(catDO,
+                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
+                                       currC = factory.or(currC, factory.comparison(versionDO,
+                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
+                                       currC = factory.or(currC, factory.comparison(nameDO,
+                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
+
+                                       defaultC = factory.and(defaultC, currC);
+                               }
+                       }
+
+                       QueryObjectModel query = factory.createQuery(source, defaultC,
+                                       null, null);
+                       QueryResult result = query.execute();
+                       return result.getNodes();
+               } catch (RepositoryException re) {
+                       throw new SlcException("Unable to refresh module list for node "
+                                       + modularDistribution, re);
+               }
+       }
+
+       @Override
+       public void setFocus() {
+               viewer.getTable().setFocus();
+       }
+
+       /** Programmatically configure the context menu */
+       protected void contextMenuAboutToShow(IMenuManager menuManager) {
+               IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
+                               .getActiveWorkbenchWindow();
+               // Build conditions
+               // Delete selected artifacts
+               CommandUtils.refreshCommand(menuManager, window, DeleteArtifacts.ID,
+                               DeleteArtifacts.DEFAULT_LABEL, DeleteArtifacts.DEFAULT_ICON,
+                               true);
+       }
+
+       private SelectionAdapter getSelectionAdapter(final int index) {
+               SelectionAdapter selectionAdapter = new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               Table table = viewer.getTable();
+                               comparator.setColumn(index);
+                               int dir = table.getSortDirection();
+                               if (table.getSortColumn() == table.getColumn(index)) {
+                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+                               } else {
+                                       dir = SWT.DOWN;
+                               }
+                               table.setSortDirection(dir);
+                               table.setSortColumn(table.getColumn(index));
+                               viewer.refresh();
+                       }
+               };
+               return selectionAdapter;
+       }
+
+       /* LOCAL CLASSES */
+       private class DistributionsContentProvider implements
+                       IStructuredContentProvider {
+               // we keep a cache of the Nodes in the content provider to be able to
+               // manage long request
+               private List<Node> nodes;
+
+               public void dispose() {
+               }
+
+               // We expect a list of nodes as a new input
+               @SuppressWarnings("unchecked")
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                       nodes = (List<Node>) newInput;
+               }
+
+               public Object[] getElements(Object arg0) {
+                       return nodes.toArray();
+               }
+       }
+
+       private class DoubleClickListener implements IDoubleClickListener {
+
+               public void doubleClick(DoubleClickEvent event) {
+                       Object obj = ((IStructuredSelection) event.getSelection())
+                                       .getFirstElement();
+                       try {
+                               if (obj instanceof Node) {
+                                       Node node = (Node) obj;
+                                       if (node.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
+                                               GenericBundleEditorInput gaei = new GenericBundleEditorInput(
+                                                               node);
+                                               DistPlugin.getDefault().getWorkbench()
+                                                               .getActiveWorkbenchWindow().getActivePage()
+                                                               .openEditor(gaei, GenericBundleEditor.ID);
+                                       }
+                               }
+                       } catch (RepositoryException re) {
+                               throw new ArgeoException(
+                                               "Repository error while getting node info", re);
+                       } catch (PartInitException pie) {
+                               throw new ArgeoException(
+                                               "Unexepected exception while opening artifact editor",
+                                               pie);
+                       }
+               }
+       }
+
+       // /**
+       // * UI Trick to put scroll bar on the table rather than on the scrollform
+       // */
+       // private void refreshLayout() {
+       // // Compute desired table size
+       // int maxH = getManagedForm().getForm().getSize().y;
+       // int maxW = getManagedForm().getForm().getParent().getSize().x;
+       // maxH = maxH - header.getSize().y;
+       // final Table table = viewer.getTable();
+       // GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true);
+       //
+       // // when table height is less than 200 px, we let the scroll bar on the
+       // // scrollForm
+       // // FIXME substract some spare space. There is room here for optimization
+       // gd.heightHint = Math.max(maxH - 35, 200);
+       // gd.widthHint = Math.max(maxW - 35, 200);
+       //
+       // table.setLayoutData(gd);
+       // getManagedForm().reflow(true);
+       // }
+
+       @Override
+       public void setActive(boolean active) {
+               super.setActive(active);
+               if (active) {
+                       // refreshLayout();
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java
deleted file mode 100644 (file)
index 68c5af7..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.client.ui.dist.editors;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.PropertyType;
-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.DynamicOperand;
-import javax.jcr.query.qom.QueryObjectModel;
-import javax.jcr.query.qom.QueryObjectModelFactory;
-import javax.jcr.query.qom.Selector;
-import javax.jcr.query.qom.StaticOperand;
-
-import org.argeo.ArgeoException;
-import org.argeo.eclipse.ui.utils.CommandUtils;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.client.ui.dist.DistImages;
-import org.argeo.slc.client.ui.dist.DistPlugin;
-import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts;
-import org.argeo.slc.client.ui.dist.utils.NodeViewerComparator;
-import org.argeo.slc.jcr.SlcNames;
-import org.argeo.slc.jcr.SlcTypes;
-import org.eclipse.jface.action.IMenuListener;
-import org.eclipse.jface.action.IMenuManager;
-import org.eclipse.jface.action.MenuManager;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.ControlListener;
-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.events.SelectionListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.ScrolledForm;
-
-/**
- * Show all modules contained in a given modular distribution as filter-able
- * table
- */
-public class ModuleListPage extends FormPage implements SlcNames {
-
-       final static String PAGE_ID = "ModuleListPage";
-
-       // Business Objects
-       private Node modularDistribution;
-       // private Node modularDistributionBase;
-
-       // This page widgets
-       private NodeViewerComparator comparator;
-       private TableViewer viewer;
-       private FormToolkit tk;
-       private Composite header;
-       private Text filterTxt;
-       private final static String FILTER_HELP_MSG = "Enter filter criterion separated by a space";
-
-       public ModuleListPage(FormEditor formEditor, String title,
-                       Node modularDistribution) {
-               super(formEditor, PAGE_ID, title);
-               this.modularDistribution = modularDistribution;
-       }
-
-       @Override
-       protected void createFormContent(IManagedForm managedForm) {
-               ScrolledForm form = managedForm.getForm();
-               tk = managedForm.getToolkit();
-
-               // Main Layout
-               GridLayout layout = new GridLayout(1, false);
-               Composite body = form.getBody();
-               body.setLayout(layout);
-               // Add the filter section
-               createFilterPart(body);
-               // Add the table
-               createTableViewer(body);
-
-               // Add a listener to enable custom resize process
-               form.addControlListener(new ControlListener() {
-                       // form.addListener(SWT.RESIZE, new Listener() does not work
-                       public void controlResized(ControlEvent e) {
-                               refreshLayout();
-                       }
-
-                       public void controlMoved(ControlEvent e) {
-                       }
-               });
-               refresh();
-       }
-
-       private void refresh() {
-               final List<Node> result = JcrUtils
-                               .nodeIteratorToList(listBundleArtifacts());
-               viewer.setInput(result);
-       }
-
-       /** Build repository request */
-       private NodeIterator listBundleArtifacts() {
-               try {
-                       Session session = modularDistribution.getSession();
-                       QueryManager queryManager = session.getWorkspace()
-                                       .getQueryManager();
-                       QueryObjectModelFactory factory = queryManager.getQOMFactory();
-
-                       Selector source = factory.selector(SlcTypes.SLC_MODULE_COORDINATES,
-                                       SlcTypes.SLC_MODULE_COORDINATES);
-
-                       // Create a dynamic operand for each property on which we want to
-                       // filter
-                       DynamicOperand catDO = factory.propertyValue(
-                                       source.getSelectorName(), SlcNames.SLC_CATEGORY);
-                       DynamicOperand nameDO = factory.propertyValue(
-                                       source.getSelectorName(), SlcNames.SLC_NAME);
-                       DynamicOperand versionDO = factory.propertyValue(
-                                       source.getSelectorName(), SlcNames.SLC_VERSION);
-
-                       String path = modularDistribution.getPath() + "/"
-                                       + SlcNames.SLC_MODULES;
-
-                       // Default Constraint: correct children
-                       Constraint defaultC = factory.descendantNode(
-                                       source.getSelectorName(), path);
-
-                       String filter = filterTxt.getText();
-
-                       // Build constraints based the textArea content
-                       if (filter != null && !"".equals(filter.trim())) {
-                               // Parse the String
-                               String[] strs = filter.trim().split(" ");
-                               for (String token : strs) {
-                                       token = token.replace('*', '%');
-                                       StaticOperand so = factory.literal(session
-                                                       .getValueFactory().createValue("%" + token + "%"));
-
-                                       Constraint currC = factory.comparison(catDO,
-                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
-                                       currC = factory.or(currC, factory.comparison(versionDO,
-                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
-                                       currC = factory.or(currC, factory.comparison(nameDO,
-                                                       QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
-
-                                       defaultC = factory.and(defaultC, currC);
-                               }
-                       }
-
-                       QueryObjectModel query = factory.createQuery(source, defaultC,
-                                       null, null);
-                       QueryResult result = query.execute();
-                       return result.getNodes();
-               } catch (RepositoryException re) {
-                       throw new SlcException("Unable to refresh module list for node "
-                                       + modularDistribution, re);
-               }
-       }
-
-       private void createFilterPart(Composite parent) {
-               header = tk.createComposite(parent);
-               GridLayout layout = new GridLayout(2, false);
-               layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0;
-               layout.horizontalSpacing = 5;
-               header.setLayout(layout);
-               GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
-               header.setLayoutData(gd);
-
-               // Text Area to filter
-               filterTxt = tk.createText(header, "", SWT.BORDER | SWT.SINGLE
-                               | SWT.SEARCH | SWT.CANCEL);
-               filterTxt.setMessage(FILTER_HELP_MSG);
-               gd = new GridData(SWT.FILL, SWT.FILL, false, false);
-               gd.grabExcessHorizontalSpace = true;
-               filterTxt.setLayoutData(gd);
-               filterTxt.addModifyListener(new ModifyListener() {
-                       public void modifyText(ModifyEvent event) {
-                               refresh();
-                       }
-               });
-
-               Button resetBtn = tk.createButton(header, null, SWT.PUSH);
-               resetBtn.setImage(DistImages.IMG_REPO_READONLY);
-               resetBtn.addSelectionListener(new SelectionListener() {
-
-                       public void widgetSelected(SelectionEvent e) {
-                               resetFilter();
-                       }
-
-                       public void widgetDefaultSelected(SelectionEvent e) {
-                       }
-               });
-
-       }
-
-       private void resetFilter() {
-               filterTxt.setText("");
-               filterTxt.setMessage(FILTER_HELP_MSG);
-       }
-
-       private void createTableViewer(Composite parent) {
-               // helpers to enable sorting by column
-               List<String> propertiesList = new ArrayList<String>();
-               List<Integer> propertyTypesList = new ArrayList<Integer>();
-
-               // Define the TableViewer
-               viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
-                               | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
-
-               // Name
-               TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
-               col.getColumn().setWidth(220);
-               col.getColumn().setText("Category");
-               col.setLabelProvider(new ColumnLabelProvider() {
-                       @Override
-                       public String getText(Object element) {
-                               return JcrUtils.get((Node) element, SlcNames.SLC_CATEGORY);
-                       }
-               });
-               col.getColumn().addSelectionListener(getSelectionAdapter(0));
-               propertiesList.add(SlcNames.SLC_CATEGORY);
-               propertyTypesList.add(PropertyType.STRING);
-
-               // Symbolic name
-               col = new TableViewerColumn(viewer, SWT.NONE);
-               col.getColumn().setWidth(220);
-               col.getColumn().setText("Name");
-               col.setLabelProvider(new ColumnLabelProvider() {
-                       @Override
-                       public String getText(Object element) {
-                               return JcrUtils.get((Node) element, SLC_NAME);
-                       }
-               });
-               col.getColumn().addSelectionListener(getSelectionAdapter(1));
-               propertiesList.add(SLC_NAME);
-               propertyTypesList.add(PropertyType.STRING);
-
-               // Version
-               col = new TableViewerColumn(viewer, SWT.NONE);
-               col.getColumn().setWidth(160);
-               col.getColumn().setText("Version");
-               col.setLabelProvider(new ColumnLabelProvider() {
-                       @Override
-                       public String getText(Object element) {
-                               return JcrUtils.get((Node) element, SLC_VERSION);
-                       }
-               });
-               col.getColumn().addSelectionListener(getSelectionAdapter(2));
-               propertiesList.add(SLC_VERSION);
-               propertyTypesList.add(PropertyType.STRING);
-
-               final Table table = viewer.getTable();
-               table.setHeaderVisible(true);
-               table.setLinesVisible(true);
-
-               viewer.setContentProvider(new DistributionsContentProvider());
-               getSite().setSelectionProvider(viewer);
-
-               comparator = new NodeViewerComparator(2,
-                               NodeViewerComparator.ASCENDING, propertiesList,
-                               propertyTypesList);
-               viewer.setComparator(comparator);
-
-               // Context Menu
-               MenuManager menuManager = new MenuManager();
-               Menu menu = menuManager.createContextMenu(viewer.getTable());
-               menuManager.addMenuListener(new IMenuListener() {
-                       public void menuAboutToShow(IMenuManager manager) {
-                               contextMenuAboutToShow(manager);
-                       }
-               });
-               viewer.getTable().setMenu(menu);
-               getSite().registerContextMenu(menuManager, viewer);
-
-               // Double click
-               viewer.addDoubleClickListener(new DoubleClickListener());
-       }
-
-       @Override
-       public void setFocus() {
-               viewer.getTable().setFocus();
-       }
-
-       /** Programmatically configure the context menu */
-       protected void contextMenuAboutToShow(IMenuManager menuManager) {
-               IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
-                               .getActiveWorkbenchWindow();
-               // Build conditions
-               // Delete selected artifacts
-               CommandUtils.refreshCommand(menuManager, window, DeleteArtifacts.ID,
-                               DeleteArtifacts.DEFAULT_LABEL, DeleteArtifacts.DEFAULT_ICON,
-                               true);
-       }
-
-       private SelectionAdapter getSelectionAdapter(final int index) {
-               SelectionAdapter selectionAdapter = new SelectionAdapter() {
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               Table table = viewer.getTable();
-                               comparator.setColumn(index);
-                               int dir = table.getSortDirection();
-                               if (table.getSortColumn() == table.getColumn(index)) {
-                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
-                               } else {
-                                       dir = SWT.DOWN;
-                               }
-                               table.setSortDirection(dir);
-                               table.setSortColumn(table.getColumn(index));
-                               viewer.refresh();
-                       }
-               };
-               return selectionAdapter;
-       }
-
-       /* LOCAL CLASSES */
-       private class DistributionsContentProvider implements
-                       IStructuredContentProvider {
-               // we keep a cache of the Nodes in the content provider to be able to
-               // manage long request
-               private List<Node> nodes;
-
-               public void dispose() {
-               }
-
-               // We expect a list of nodes as a new input
-               @SuppressWarnings("unchecked")
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-                       nodes = (List<Node>) newInput;
-               }
-
-               public Object[] getElements(Object arg0) {
-                       return nodes.toArray();
-               }
-       }
-
-       private class DoubleClickListener implements IDoubleClickListener {
-
-               public void doubleClick(DoubleClickEvent event) {
-                       Object obj = ((IStructuredSelection) event.getSelection())
-                                       .getFirstElement();
-                       try {
-                               if (obj instanceof Node) {
-                                       Node node = (Node) obj;
-                                       if (node.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
-                                               GenericBundleEditorInput gaei = new GenericBundleEditorInput(
-                                                               node);
-                                               DistPlugin.getDefault().getWorkbench()
-                                                               .getActiveWorkbenchWindow().getActivePage()
-                                                               .openEditor(gaei, GenericBundleEditor.ID);
-                                       }
-                               }
-                       } catch (RepositoryException re) {
-                               throw new ArgeoException(
-                                               "Repository error while getting node info", re);
-                       } catch (PartInitException pie) {
-                               throw new ArgeoException(
-                                               "Unexepected exception while opening artifact editor",
-                                               pie);
-                       }
-               }
-       }
-
-       /**
-        * UI Trick to put scroll bar on the table rather than on the scrollform
-        */
-       private void refreshLayout() {
-               // Compute desired table size
-               int maxH = getManagedForm().getForm().getSize().y;
-               int maxW = getManagedForm().getForm().getParent().getSize().x;
-               maxH = maxH - header.getSize().y;
-               final Table table = viewer.getTable();
-               GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true);
-
-               // when table height is less than 200 px, we let the scroll bar on the
-               // scrollForm
-               // FIXME substract some spare space. There is room here for optimization
-               gd.heightHint = Math.max(maxH - 35, 200);
-               gd.widthHint = Math.max(maxW - 35, 200);
-
-               table.setLayoutData(gd);
-               getManagedForm().reflow(true);
-       }
-
-       @Override
-       public void setActive(boolean active) {
-               super.setActive(active);
-               if (active) {
-                       refreshLayout();
-               }
-       }
-}
\ No newline at end of file
index 7f67a73a36d0c9aae0258acc1745ad14cef98e83..6479eb5343b6814f8dadd007ecb9d5377bb50a85 100644 (file)
@@ -114,7 +114,7 @@ public class WkspCategoryBaseListPage extends FormPage implements SlcNames {
                ScrolledForm form = managedForm.getForm();
                tk = managedForm.getToolkit();
 
-               form.setText("Define Relevant Category");
+               form.setText("Define Relevant Categories");
                form.setMessage("Choose in the below list "
                                + "the categories that can be used as base for "
                                + "modular distributions maintained via the current workspace",
index 35e3f21dd40f01ad2bec30df308913719d180986..fab28ff379e54974ea3dc6fd1b33c96a9657e6bf 100644 (file)
@@ -35,6 +35,19 @@ public class ModularDistBaseElem extends DistParentElem {
                this.type = type;
        }
 
+       public Node getCategoryBase() {
+               // TODO clean this
+               if (type.equals(AETHER_CATEGORY_BASE))
+                       return artifactBase;
+               else
+                       try {
+                               return artifactBase.getParent();
+                       } catch (RepositoryException e) {
+                               throw new SlcException("unable tyo get parent node for "
+                                               + artifactBase, e);
+                       }
+       }
+
        /**
         * Override normal behavior to initialize children only when first requested
         */
@@ -73,7 +86,7 @@ public class ModularDistBaseElem extends DistParentElem {
                }
        }
 
-       public NodeIterator getDistVersions() {
+       private NodeIterator getDistVersions() {
                try {
                        if (AETHER_CATEGORY_BASE.equals(type))
                                return null;
index c365a833cedc3247d0f2584e78ec75060466934b..2838863173137385986c2816d043bc8193b2fecc 100644 (file)
@@ -34,6 +34,7 @@ import org.argeo.slc.client.ui.dist.commands.Fetch;
 import org.argeo.slc.client.ui.dist.commands.MergeWorkspaces;
 import org.argeo.slc.client.ui.dist.commands.NormalizeDistribution;
 import org.argeo.slc.client.ui.dist.commands.NormalizeWorkspace;
+import org.argeo.slc.client.ui.dist.commands.OpenGenerateBinariesWizard;
 import org.argeo.slc.client.ui.dist.commands.PublishWorkspace;
 import org.argeo.slc.client.ui.dist.commands.RefreshDistributionsView;
 import org.argeo.slc.client.ui.dist.commands.RegisterRepository;
@@ -45,6 +46,7 @@ import org.argeo.slc.client.ui.dist.controllers.DistTreeContentProvider;
 import org.argeo.slc.client.ui.dist.controllers.DistTreeDoubleClickListener;
 import org.argeo.slc.client.ui.dist.controllers.DistTreeLabelProvider;
 import org.argeo.slc.client.ui.dist.model.DistParentElem;
+import org.argeo.slc.client.ui.dist.model.ModularDistBaseElem;
 import org.argeo.slc.client.ui.dist.model.RepoElem;
 import org.argeo.slc.client.ui.dist.model.WkspGroupElem;
 import org.argeo.slc.client.ui.dist.model.WorkspaceElem;
@@ -157,7 +159,7 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                String targetRepoPath = null, workspaceName = null, workspacePrefix = null;
                                // String targetRepoUri = null;
                                // Build conditions depending on element type
-                               boolean isDistribElem = false, isRepoElem = false, isDistribGroupElem = false;
+                               boolean isDistribElem = false, isModularDistBaseElem = false, isRepoElem = false, isDistribGroupElem = false;
                                boolean isLocal = false, isReadOnly = true;
 
                                RepoElem re = null;
@@ -174,6 +176,12 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                        isRepoElem = true;
                                        isLocal = re.inHome();
                                        isReadOnly = re.isReadOnly();
+                               } else if (firstElement instanceof ModularDistBaseElem) {
+                                       ModularDistBaseElem mdbe = (ModularDistBaseElem) firstElement;
+                                       re = (RepoElem) mdbe.getParent().getParent().getParent();
+                                       isModularDistBaseElem = true;
+                                       isLocal = re.inHome();
+                                       isReadOnly = re.isReadOnly();
                                } else if (firstElement instanceof WkspGroupElem) {
                                        WkspGroupElem wge = (WkspGroupElem) firstElement;
                                        isReadOnly = wge.isReadOnly();
@@ -229,8 +237,8 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                params.put(Fetch.PARAM_TARGET_REPO_PATH, targetRepoPath);
                                CommandUtils.refreshParametrizedCommand(menuManager, window,
                                                Fetch.ID, Fetch.DEFAULT_LABEL, Fetch.DEFAULT_ICON,
-                                               isRepoElem && isLocal && singleElement
-                                                               && !isReadOnly, params);
+                                               isRepoElem && isLocal && singleElement && !isReadOnly,
+                                               params);
 
                                // Normalize workspace
                                params = new HashMap<String, String>();
@@ -300,7 +308,13 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                CommandUtils.refreshParametrizedCommand(submenu, window,
                                                RunInOsgi.ID, RunInOsgi.DEFAULT_LABEL,
                                                RunInOsgi.DEFAULT_ICON, isDistribElem && singleElement
-                                                               && isLocal, params);
+                                                               && isLocal, params);// Run in OSGi
+
+                               CommandUtils.refreshCommand(submenu, window,
+                                               OpenGenerateBinariesWizard.ID,
+                                               OpenGenerateBinariesWizard.DEFAULT_LABEL,
+                                               OpenGenerateBinariesWizard.DEFAULT_ICON,
+                                               isModularDistBaseElem && !isReadOnly);
 
                                if (submenu.getSize() > 0)
                                        menuManager.add(submenu);
diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java
new file mode 100644 (file)
index 0000000..e0474a0
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.client.ui.dist.wizards;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoMonitor;
+import org.argeo.eclipse.ui.EclipseArgeoMonitor;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.client.ui.dist.DistPlugin;
+import org.argeo.slc.client.ui.dist.PrivilegedJob;
+import org.argeo.slc.client.ui.dist.utils.ViewerUtils;
+import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.RepoConstants;
+import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.maven.GenerateBinaries;
+import org.argeo.slc.repo.maven.IndexDistribution;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.sonatype.aether.artifact.Artifact;
+
+/**
+ * Defines parameters to generate binaries (e.g. a specific modular
+ * distribution) using a {@link IndexDistribution} object
+ */
+public class GenerateBinariesWizard extends Wizard {
+       private final static Log log = LogFactory
+                       .getLog(GenerateBinariesWizard.class);
+
+       // Business objects
+       private Node groupNode;
+
+       // The pages
+       private RecapPage recapPage;
+
+       // Controls with parameters
+       private Button overridePomsBtn;
+       private Text versionTxt;
+       private Text latestVersionTxt;
+       private Text highestArtifactVersionTxt;
+
+       // private CheckboxTableViewer wkspViewer;
+
+       public GenerateBinariesWizard(Node groupNode) {
+               super();
+               this.groupNode = groupNode;
+       }
+
+       @Override
+       public void dispose() {
+               super.dispose();
+       }
+
+       @Override
+       public void addPages() {
+               try {
+                       recapPage = new RecapPage();
+                       addPage(recapPage);
+                       setWindowTitle("Define Binary Generation Procedure");
+               } catch (Exception e) {
+                       throw new SlcException("Cannot add page to wizard ", e);
+               }
+       }
+
+       @Override
+       public boolean performFinish() {
+               if (!canFinish())
+                       return false;
+               try {
+                       String msg = "Your are about to normalize group, do you really want to proceed ?";
+
+                       boolean result = MessageDialog.openConfirm(DistPlugin.getDefault()
+                                       .getWorkbench().getDisplay().getActiveShell(),
+                                       "Confirm Process Launch", msg);
+
+                       if (result) {
+                               GenerateBinaryJob job = new GenerateBinaryJob(groupNode,
+                                               versionTxt.getText(), overridePomsBtn.getSelection());
+                               job.setUser(true);
+                               job.schedule();
+                       }
+               } catch (Exception e) {
+                       throw new SlcException(
+                                       "Unexpected error while launching the fetch", e);
+               }
+               return true;
+       }
+
+       // ///////////////////////////////
+       // ////// THE PAGES
+       private class RecapPage extends WizardPage {
+
+               private TableViewer recapViewer;
+
+               public RecapPage() {
+                       super("Define parameters and launch");
+                       setTitle("Define parameters and launch");
+               }
+
+               @Override
+               public boolean isPageComplete() {
+                       return isCurrentPage();
+               }
+
+               public IWizardPage getNextPage() {
+                       // always last....
+                       return null;
+               }
+
+               @Override
+               public void setVisible(boolean visible) {
+                       if (visible) {
+
+                       }
+                       super.setVisible(visible);
+               }
+
+               private void refreshValues() {
+                       try {
+                               GenerateBinaries gb = GenerateBinaries.preProcessGroupNode(
+                                               groupNode, null);
+
+                               List<Artifact> binaries = new ArrayList<Artifact>();
+                               binaries.addAll(gb.getBinaries());
+
+                               Artifact highestVersion = gb.getHighestArtifactVersion();
+                               if (highestVersion != null)
+                                       highestArtifactVersionTxt.setText(highestVersion
+                                                       .getBaseVersion());
+
+                               if (groupNode.hasNode(RepoConstants.BINARIES_ARTIFACT_ID)) {
+                                       Node binaryNode = groupNode
+                                                       .getNode(RepoConstants.BINARIES_ARTIFACT_ID);
+                                       Artifact currHighestVersion = null;
+                                       for (NodeIterator ni = binaryNode.getNodes(); ni.hasNext();) {
+                                               Node currN = ni.nextNode();
+                                               if (currN
+                                                               .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) {
+                                                       Artifact currVersion = RepoUtils.asArtifact(currN);
+
+                                                       if (currHighestVersion == null
+                                                                       || currVersion.getBaseVersion()
+                                                                                       .compareTo(
+                                                                                                       currHighestVersion
+                                                                                                                       .getBaseVersion()) > 0)
+                                                               currHighestVersion = currVersion;
+                                               }
+                                       }
+                                       if (currHighestVersion != null)
+                                               latestVersionTxt.setText(highestVersion
+                                                               .getBaseVersion());
+                               }
+
+                               recapViewer.setInput(binaries);
+                               recapViewer.refresh();
+                       } catch (RepositoryException re) {
+                               throw new SlcException("Unable to get repositories URIs", re);
+                       }
+               }
+
+               public void createControl(Composite parent) {
+                       Composite composite = new Composite(parent, SWT.NO_FOCUS);
+                       composite.setLayout(new GridLayout(2, false));
+
+                       versionTxt = createLT(composite, "Version");
+                       latestVersionTxt = createLT(composite, "Latest version");
+                       latestVersionTxt.setEditable(false);
+                       highestArtifactVersionTxt = createLT(composite,
+                                       "Highest version in current category");
+                       highestArtifactVersionTxt.setEditable(false);
+
+                       overridePomsBtn = createLC(composite, "Override POMs");
+                       setMessage("Configure Maven Indexing", IMessageProvider.NONE);
+
+                       Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL
+                                       | SWT.BORDER);
+                       table.setLinesVisible(true);
+                       table.setHeaderVisible(true);
+                       table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2,
+                                       1));
+                       recapViewer = new TableViewer(table);
+
+                       // Artifact columns
+                       TableViewerColumn column = ViewerUtils.createTableViewerColumn(
+                                       recapViewer, "Name", SWT.NONE, 250);
+                       column.setLabelProvider(new ColumnLabelProvider() {
+                               @Override
+                               public String getText(Object element) {
+                                       return ((Artifact) element).getArtifactId();
+                               }
+                       });
+
+                       column = ViewerUtils.createTableViewerColumn(recapViewer,
+                                       "Version", SWT.NONE, 250);
+                       column.setLabelProvider(new ColumnLabelProvider() {
+                               @Override
+                               public String getText(Object element) {
+                                       return ((Artifact) element).getBaseVersion();
+                               }
+                       });
+
+                       recapViewer.setContentProvider(new IStructuredContentProvider() {
+                               List<Artifact> artifacts;
+
+                               public void inputChanged(Viewer viewer, Object oldInput,
+                                               Object newInput) {
+                                       artifacts = (List<Artifact>) newInput;
+                                       if (artifacts != null)
+                                               recapViewer.refresh();
+                               }
+
+                               public void dispose() {
+                               }
+
+                               public Object[] getElements(Object inputElement) {
+                                       return artifacts == null ? null : artifacts.toArray();
+                               }
+                       });
+
+                       // A basic comparator
+                       recapViewer.setComparator(new ViewerComparator());
+                       refreshValues();
+                       setControl(composite);
+               }
+       }
+
+       /** Creates label and text. */
+       protected Text createLT(Composite parent, String label) {
+               new Label(parent, SWT.NONE).setText(label);
+               Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER
+                               | SWT.NONE);
+               text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               return text;
+       }
+
+       /** Creates label and check. */
+       protected Button createLC(Composite parent, String label) {
+               new Label(parent, SWT.NONE).setText(label);
+               Button check = new Button(parent, SWT.CHECK);
+               check.setSelection(false);
+               check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               return check;
+       }
+
+       /**
+        * Define the privileged job that will be run asynchronously to real
+        * indexing
+        */
+       private class GenerateBinaryJob extends PrivilegedJob {
+               private Node groupBaseNode;
+               private String version;
+               private boolean overridePoms;
+
+               public GenerateBinaryJob(Node groupBaseNode, String version,
+                               boolean overridePoms) {
+                       super("Fetch");
+                       this.groupBaseNode = groupBaseNode;
+                       this.version = version;
+                       this.overridePoms = overridePoms;
+               }
+
+               @Override
+               protected IStatus doRun(IProgressMonitor progressMonitor) {
+                       try {
+                               ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor);
+                               GenerateBinaries.processGroupNode(groupBaseNode, version,
+                                               overridePoms, monitor);
+                       } catch (Exception e) {
+                               if (log.isDebugEnabled())
+                                       e.printStackTrace();
+                               return new Status(IStatus.ERROR, DistPlugin.ID,
+                                               "Cannot normalize group", e);
+                       }
+                       return Status.OK_STATUS;
+               }
+       }
+
+       // ////////////////////////////
+       // // Helpers
+}
\ No newline at end of file
index 18e86492844a71e121d499d33a21e1877eadfa46..6ae38bf3a5159894c9980aea473683a78f16ab62 100644 (file)
@@ -248,6 +248,7 @@ public class RepoSync implements Runnable {
                        if (log.isDebugEnabled())
                                log.debug("Synced " + sourceSession.getWorkspace().getName());
                } catch (Exception e) {
+                       e.printStackTrace();
                        throw new SlcException("Cannot sync "
                                        + sourceSession.getWorkspace().getName() + " to "
                                        + targetSession.getWorkspace().getName(), e);
@@ -315,7 +316,8 @@ public class RepoSync implements Runnable {
                        copyProperties(sourceNode, targetNode);
 
                        // next level
-                       for (NodeIterator ni = sourceNode.getNodes(); ni.hasNext();) {
+                       NodeIterator ni = sourceNode.getNodes();
+                       while (ni != null && ni.hasNext()) {
                                Node sourceChild = ni.nextNode();
                                syncNode(sourceChild, targetSession);
                        }
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java
new file mode 100644 (file)
index 0000000..a1e2a07
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.repo.maven;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.jcr.Credentials;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoMonitor;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.aether.ArtifactIdComparator;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.ArtifactIndexer;
+import org.argeo.slc.repo.RepoConstants;
+import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.osgi.OsgiProfile;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+/**
+ * Make sure that all JCR metadata and Maven metadata are consistent for this
+ * group of OSGi bundles.
+ */
+public class GenerateBinaries implements Runnable, SlcNames {
+       private final static Log log = LogFactory.getLog(GenerateBinaries.class);
+
+       // Connection info
+       private Repository repository;
+       private Credentials credentials;
+       private String workspace;
+
+       // Business info
+       private String groupId;
+       private String parentPomCoordinates;
+       private Boolean overridePoms = false;
+       private String version = null;
+
+       // Constants
+       private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
+       private List<String> excludedSuffixes = new ArrayList<String>();
+       /** TODO make it more generic */
+       private List<String> systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6
+                       .getSystemPackages();
+
+       private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
+
+       // Local indexes
+       private Map<String, String> packagesToSymbolicNames = new HashMap<String, String>();
+       private Map<String, Node> symbolicNamesToNodes = new HashMap<String, Node>();
+       private Set<Artifact> binaries = new TreeSet<Artifact>(
+                       new ArtifactIdComparator());
+       private Set<Artifact> sources = new TreeSet<Artifact>(
+                       new ArtifactIdComparator());
+       private Node allArtifactsHighestVersion;
+
+       public void run() {
+               Session session = null;
+               try {
+                       session = repository.login(workspace);
+                       Node groupNode = session.getNode(MavenConventionsUtils.groupPath(
+                                       artifactBasePath, groupId));
+                       internalPreProcessing(groupNode, null);
+                       processGroupNode(groupNode, null);
+               } catch (Exception e) {
+                       throw new SlcException("Cannot normalize group " + groupId + " in "
+                                       + workspace, e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+       }
+
+       public static void processGroupNode(Node groupNode, String version,
+                       Boolean overridePoms, ArgeoMonitor monitor)
+                       throws RepositoryException {
+               // TODO set artifactsBase based on group node
+               GenerateBinaries gb = new GenerateBinaries();
+               String groupId = groupNode.getProperty(SlcNames.SLC_GROUP_BASE_ID)
+                               .getString();
+               gb.setGroupId(groupId);
+               gb.setVersion(version);
+               gb.setOverridePoms(overridePoms);
+               // TODO use already done pre-processing
+               gb.internalPreProcessing(groupNode, monitor);
+               gb.processGroupNode(groupNode, monitor);
+       }
+
+       /** Only builds local indexes. Does not change anything in the local Session */
+       public static GenerateBinaries preProcessGroupNode(Node groupNode,
+                       ArgeoMonitor monitor) throws RepositoryException {
+               // TODO set artifactsBase based on group node
+               GenerateBinaries gb = new GenerateBinaries();
+               String groupId = groupNode.getProperty(SlcNames.SLC_GROUP_BASE_ID)
+                               .getString();
+               gb.setGroupId(groupId);
+               // gb.setVersion(version);
+               // gb.setOverridePoms(overridePoms);
+               gb.internalPreProcessing(groupNode, monitor);
+               return gb;
+       }
+
+       // exposes indexes. to display results of the pre-processing phase.
+       public Set<Artifact> getBinaries() {
+               return binaries;
+       }
+
+       public Artifact getHighestArtifactVersion() throws RepositoryException {
+               return allArtifactsHighestVersion == null ? null : RepoUtils
+                               .asArtifact(allArtifactsHighestVersion);
+       }
+
+       protected void internalPreProcessing(Node groupNode, ArgeoMonitor monitor)
+                       throws RepositoryException {
+               if (monitor != null)
+                       monitor.subTask("Pre processing group " + groupId);
+
+               // Process all direct children nodes,
+               // gathering latest versions of all artifact base
+               allArtifactsHighestVersion = null;
+               // Session session = groupNode.getSession();
+               aBases: for (NodeIterator aBases = groupNode.getNodes(); aBases
+                               .hasNext();) {
+                       Node aBase = aBases.nextNode();
+                       if (aBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) {
+                               Node highestAVersion = getArtifactLatestVersion(aBase);
+                               if (highestAVersion == null)
+                                       continue aBases;
+                               else {
+                                       // retrieve relevant child node
+                                       for (NodeIterator files = highestAVersion.getNodes(); files
+                                                       .hasNext();) {
+                                               Node file = files.nextNode();
+                                               if (file.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
+                                                       preProcessBundleArtifact(file);
+                                                       if (log.isDebugEnabled())
+                                                               log.debug("Pre-processed " + file.getName());
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (log.isDebugEnabled()) {
+                       int bundleCount = symbolicNamesToNodes.size();
+                       log.debug("" + bundleCount + " bundles have been indexed for "
+                                       + groupId);
+               }
+       }
+
+       /** Does the real job : writes JCR META-DATA and generates binaries */
+       protected void processGroupNode(Node groupNode, ArgeoMonitor monitor)
+                       throws RepositoryException {
+               if (monitor != null)
+                       monitor.subTask("Processing group " + groupId);
+
+               Session session = groupNode.getSession();
+
+               // if version not set or empty, use the highest version
+               // useful when indexing a product maven repository where
+               // all artifacts have the same version for a given release
+               // => the version can then be left empty
+               if (version == null || version.trim().equals(""))
+                       if (allArtifactsHighestVersion != null)
+                               version = allArtifactsHighestVersion.getProperty(
+                                               SLC_ARTIFACT_VERSION).getString();
+                       else
+                               throw new SlcException("Group version " + version
+                                               + " is empty.");
+
+               int bundleCount = symbolicNamesToNodes.size();
+
+               int count = 1;
+               for (Node bundleNode : symbolicNamesToNodes.values()) {
+                       processBundleArtifact(bundleNode);
+                       bundleNode.getSession().save();
+                       if (log.isDebugEnabled())
+                               log.debug(count + "/" + bundleCount + " Processed "
+                                               + bundleNode.getName());
+                       count++;
+               }
+
+               // indexes
+               Set<Artifact> indexes = new TreeSet<Artifact>(
+                               new ArtifactIdComparator());
+               Artifact indexArtifact = writeIndex(session,
+                               RepoConstants.BINARIES_ARTIFACT_ID, binaries);
+               indexes.add(indexArtifact);
+               indexArtifact = writeIndex(session, RepoConstants.SOURCES_ARTIFACT_ID,
+                               sources);
+               indexes.add(indexArtifact);
+               // sdk
+               writeIndex(session, RepoConstants.SDK_ARTIFACT_ID, indexes);
+               if (monitor != null)
+                       monitor.worked(1);
+       }
+
+       // Helpers
+       private Node getArtifactLatestVersion(Node artifactBase) {
+               try {
+                       Node highestAVersion = null;
+                       for (NodeIterator aVersions = artifactBase.getNodes(); aVersions
+                                       .hasNext();) {
+                               Node aVersion = aVersions.nextNode();
+                               if (aVersion.isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) {
+                                       if (highestAVersion == null) {
+                                               highestAVersion = aVersion;
+                                               if (allArtifactsHighestVersion == null)
+                                                       allArtifactsHighestVersion = aVersion;
+                                               // Correctly handle following arrival order:
+                                               // Name1 - V1, name2 - V3
+                                               else {
+                                                       Version cachedHighestVersion = extractOsgiVersion(allArtifactsHighestVersion);
+                                                       Version currVersion = extractOsgiVersion(aVersion);
+                                                       if (currVersion.compareTo(cachedHighestVersion) > 0)
+                                                               allArtifactsHighestVersion = aVersion;
+                                               }
+                                       } else {
+                                               Version currVersion = extractOsgiVersion(aVersion);
+                                               Version currentHighestVersion = extractOsgiVersion(highestAVersion);
+                                               if (currVersion.compareTo(currentHighestVersion) > 0) {
+                                                       highestAVersion = aVersion;
+                                               }
+                                               if (currVersion
+                                                               .compareTo(extractOsgiVersion(allArtifactsHighestVersion)) > 0) {
+                                                       allArtifactsHighestVersion = aVersion;
+                                               }
+                                       }
+
+                               }
+                       }
+                       return highestAVersion;
+               } catch (RepositoryException re) {
+                       throw new SlcException("Unable to get latest version for node "
+                                       + artifactBase, re);
+               }
+       }
+
+       private Version extractOsgiVersion(Node artifactVersion)
+                       throws RepositoryException {
+               String rawVersion = artifactVersion.getProperty(SLC_ARTIFACT_VERSION)
+                               .getString();
+               String cleanVersion = rawVersion.replace("-SNAPSHOT", ".SNAPSHOT");
+               return new Version(cleanVersion);
+       }
+
+       protected void preProcessBundleArtifact(Node bundleNode)
+                       throws RepositoryException {
+
+               String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME);
+               if (symbolicName.endsWith(".source")) {
+                       // TODO make a shared node with classifier 'sources'?
+                       String bundleName = RepoUtils
+                                       .extractBundleNameFromSourceName(symbolicName);
+                       for (String excludedSuffix : excludedSuffixes) {
+                               if (bundleName.endsWith(excludedSuffix))
+                                       return;// skip adding to sources
+                       }
+                       sources.add(RepoUtils.asArtifact(bundleNode));
+                       return;
+               }
+
+               NodeIterator exportPackages = bundleNode.getNodes(SLC_
+                               + Constants.EXPORT_PACKAGE);
+               while (exportPackages.hasNext()) {
+                       Node exportPackage = exportPackages.nextNode();
+                       String pkg = JcrUtils.get(exportPackage, SLC_NAME);
+                       packagesToSymbolicNames.put(pkg, symbolicName);
+               }
+
+               symbolicNamesToNodes.put(symbolicName, bundleNode);
+               for (String excludedSuffix : excludedSuffixes) {
+                       if (symbolicName.endsWith(excludedSuffix))
+                               return;// skip adding to binaries
+               }
+               binaries.add(RepoUtils.asArtifact(bundleNode));
+
+               if (bundleNode.getSession().hasPendingChanges())
+                       throw new SlcException("Pending changes in the session, "
+                                       + "this should not be true here.");
+               // bundleNode.getSession().save();
+       }
+
+       protected void processBundleArtifact(Node bundleNode)
+                       throws RepositoryException {
+               Node artifactFolder = bundleNode.getParent();
+               String baseName = FilenameUtils.getBaseName(bundleNode.getName());
+
+               // pom
+               String pomName = baseName + ".pom";
+               if (artifactFolder.hasNode(pomName) && !overridePoms)
+                       return;// skip
+
+               String pom = generatePomForBundle(bundleNode);
+               Node pomNode = JcrUtils.copyBytesAsFile(artifactFolder, pomName,
+                               pom.getBytes());
+               // checksum
+               String bundleSha = JcrUtils.checksumFile(bundleNode, "SHA-1");
+               JcrUtils.copyBytesAsFile(artifactFolder,
+                               bundleNode.getName() + ".sha1", bundleSha.getBytes());
+               String pomSha = JcrUtils.checksumFile(pomNode, "SHA-1");
+               JcrUtils.copyBytesAsFile(artifactFolder, pomNode.getName() + ".sha1",
+                               pomSha.getBytes());
+       }
+
+       // Writers
+       private Artifact writeIndex(Session session, String artifactId,
+                       Set<Artifact> artifacts) throws RepositoryException {
+               Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom",
+                               version);
+               Artifact parentArtifact = parentPomCoordinates != null ? new DefaultArtifact(
+                               parentPomCoordinates) : null;
+               String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact,
+                               artifacts, parentArtifact);
+               Node node = RepoUtils.copyBytesAsArtifact(
+                               session.getNode(artifactBasePath), artifact, pom.getBytes());
+               artifactIndexer.index(node);
+
+               // TODO factorize
+               String pomSha = JcrUtils.checksumFile(node, "SHA-1");
+               JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".sha1",
+                               pomSha.getBytes());
+               String pomMd5 = JcrUtils.checksumFile(node, "MD5");
+               JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".md5",
+                               pomMd5.getBytes());
+               session.save();
+               return artifact;
+       }
+
+       private String generatePomForBundle(Node n) throws RepositoryException {
+               String ownSymbolicName = JcrUtils.get(n, SLC_SYMBOLIC_NAME);
+
+               StringBuffer p = new StringBuffer();
+
+               // XML header
+               p.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               p.append("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n");
+               p.append("<modelVersion>4.0.0</modelVersion>");
+
+               // Artifact
+               p.append("<groupId>").append(JcrUtils.get(n, SLC_GROUP_ID))
+                               .append("</groupId>\n");
+               p.append("<artifactId>").append(JcrUtils.get(n, SLC_ARTIFACT_ID))
+                               .append("</artifactId>\n");
+               p.append("<version>").append(JcrUtils.get(n, SLC_ARTIFACT_VERSION))
+                               .append("</version>\n");
+               p.append("<packaging>pom</packaging>\n");
+               if (n.hasProperty(SLC_ + Constants.BUNDLE_NAME))
+                       p.append("<name>")
+                                       .append(JcrUtils.get(n, SLC_ + Constants.BUNDLE_NAME))
+                                       .append("</name>\n");
+               if (n.hasProperty(SLC_ + Constants.BUNDLE_DESCRIPTION))
+                       p.append("<description>")
+                                       .append(JcrUtils
+                                                       .get(n, SLC_ + Constants.BUNDLE_DESCRIPTION))
+                                       .append("</description>\n");
+
+               // Dependencies
+               Set<String> dependenciesSymbolicNames = new TreeSet<String>();
+               Set<String> optionalSymbolicNames = new TreeSet<String>();
+               NodeIterator importPackages = n.getNodes(SLC_
+                               + Constants.IMPORT_PACKAGE);
+               while (importPackages.hasNext()) {
+                       Node importPackage = importPackages.nextNode();
+                       String pkg = JcrUtils.get(importPackage, SLC_NAME);
+                       if (packagesToSymbolicNames.containsKey(pkg)) {
+                               String dependencySymbolicName = packagesToSymbolicNames
+                                               .get(pkg);
+                               if (JcrUtils.check(importPackage, SLC_OPTIONAL))
+                                       optionalSymbolicNames.add(dependencySymbolicName);
+                               else
+                                       dependenciesSymbolicNames.add(dependencySymbolicName);
+                       } else {
+                               if (!JcrUtils.check(importPackage, SLC_OPTIONAL)
+                                               && !systemPackages.contains(pkg))
+                                       log.warn("No bundle found for pkg " + pkg);
+                       }
+               }
+
+               if (n.hasNode(SLC_ + Constants.FRAGMENT_HOST)) {
+                       String fragmentHost = JcrUtils.get(
+                                       n.getNode(SLC_ + Constants.FRAGMENT_HOST),
+                                       SLC_SYMBOLIC_NAME);
+                       dependenciesSymbolicNames.add(fragmentHost);
+               }
+
+               // TODO require bundles
+
+               List<Node> dependencyNodes = new ArrayList<Node>();
+               for (String depSymbName : dependenciesSymbolicNames) {
+                       if (depSymbName.equals(ownSymbolicName))
+                               continue;// skip self
+
+                       if (symbolicNamesToNodes.containsKey(depSymbName))
+                               dependencyNodes.add(symbolicNamesToNodes.get(depSymbName));
+                       else
+                               log.warn("Could not find node for " + depSymbName);
+               }
+               List<Node> optionalDependencyNodes = new ArrayList<Node>();
+               for (String depSymbName : optionalSymbolicNames) {
+                       if (symbolicNamesToNodes.containsKey(depSymbName))
+                               optionalDependencyNodes.add(symbolicNamesToNodes
+                                               .get(depSymbName));
+                       else
+                               log.warn("Could not find node for " + depSymbName);
+               }
+
+               p.append("<dependencies>\n");
+               for (Node dependencyNode : dependencyNodes) {
+                       p.append("<dependency>\n");
+                       p.append("\t<groupId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
+                                       .append("</groupId>\n");
+                       p.append("\t<artifactId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
+                                       .append("</artifactId>\n");
+                       p.append("</dependency>\n");
+               }
+
+               if (optionalDependencyNodes.size() > 0)
+                       p.append("<!-- OPTIONAL -->\n");
+               for (Node dependencyNode : optionalDependencyNodes) {
+                       p.append("<dependency>\n");
+                       p.append("\t<groupId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
+                                       .append("</groupId>\n");
+                       p.append("\t<artifactId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
+                                       .append("</artifactId>\n");
+                       p.append("\t<optional>true</optional>\n");
+                       p.append("</dependency>\n");
+               }
+               p.append("</dependencies>\n");
+
+               // Dependency management
+               p.append("<dependencyManagement>\n");
+               p.append("<dependencies>\n");
+               p.append("<dependency>\n");
+               p.append("\t<groupId>").append(groupId).append("</groupId>\n");
+               p.append("\t<artifactId>")
+                               .append(ownSymbolicName.endsWith(".source") ? RepoConstants.SOURCES_ARTIFACT_ID
+                                               : RepoConstants.BINARIES_ARTIFACT_ID)
+                               .append("</artifactId>\n");
+               p.append("\t<version>").append(version).append("</version>\n");
+               p.append("\t<type>pom</type>\n");
+               p.append("\t<scope>import</scope>\n");
+               p.append("</dependency>\n");
+               p.append("</dependencies>\n");
+               p.append("</dependencyManagement>\n");
+
+               p.append("</project>\n");
+               return p.toString();
+       }
+
+       /* SETTERS */
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public void setWorkspace(String workspace) {
+               this.workspace = workspace;
+       }
+
+       public void setGroupId(String groupId) {
+               this.groupId = groupId;
+       }
+
+       public void setParentPomCoordinates(String parentPomCoordinates) {
+               this.parentPomCoordinates = parentPomCoordinates;
+       }
+
+       public void setArtifactBasePath(String artifactBasePath) {
+               this.artifactBasePath = artifactBasePath;
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+       public void setExcludedSuffixes(List<String> excludedSuffixes) {
+               this.excludedSuffixes = excludedSuffixes;
+       }
+
+       public void setOverridePoms(Boolean overridePoms) {
+               this.overridePoms = overridePoms;
+       }
+
+       public void setArtifactIndexer(ArtifactIndexer artifactIndexer) {
+               this.artifactIndexer = artifactIndexer;
+       }
+}
\ No newline at end of file
index 0d1eded0847b9b7131cd4bd7db42e3c5f6e28efa..34e1aee249e0d24fee5d3c76190bb59b64efc536 100644 (file)
@@ -178,8 +178,9 @@ public class NormalizeGroup implements Runnable, SlcNames {
                                version = allArtifactsHighestVersion.getProperty(
                                                SLC_ARTIFACT_VERSION).getString();
                        else
-                               throw new SlcException("Group version " + version
-                                               + " is empty.");
+                               version = "0.0";
+//                             throw new SlcException("Group version " + version
+//                                             + " is empty.");
 
                int bundleCount = symbolicNamesToNodes.size();
                if (log.isDebugEnabled())
@@ -243,12 +244,8 @@ public class NormalizeGroup implements Runnable, SlcNames {
 
        protected void preProcessBundleArtifact(Node bundleNode)
                        throws RepositoryException {
-               // we assume nodes are already indexed
-               // artifactIndexer.index(bundleNode);
-               // jarFileIndexer.index(bundleNode);
 
                String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME);
-
                if (symbolicName.endsWith(".source")) {
                        // TODO make a shared node with classifier 'sources'?
                        String bundleName = RepoUtils
@@ -313,7 +310,6 @@ public class NormalizeGroup implements Runnable, SlcNames {
                p.append("<modelVersion>4.0.0</modelVersion>");
 
                // Artifact
-               // p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
                p.append("<groupId>").append(JcrUtils.get(n, SLC_GROUP_ID))
                                .append("</groupId>\n");
                p.append("<artifactId>").append(JcrUtils.get(n, SLC_ARTIFACT_ID))
@@ -362,6 +358,8 @@ public class NormalizeGroup implements Runnable, SlcNames {
 
                // TODO require bundles
 
+               
+               
                List<Node> dependencyNodes = new ArrayList<Node>();
                for (String depSymbName : dependenciesSymbolicNames) {
                        if (depSymbName.equals(ownSymbolicName))
index bc3300515f4a8c1a400b16fdc4c293606c145f07..d6ddd19218d7d5c04f4717e6d38789eabd3c0e46 100644 (file)
@@ -105,6 +105,7 @@ public interface SlcNames {
        // shared OSGi
        public final static String SLC_SYMBOLIC_NAME = "slc:symbolic-name";
        public final static String SLC_BUNDLE_VERSION = "slc:bundle-version";
+       public final static String SLC_BUNDLE_DESCRIPTION = "slc:Bundle-Description";
 
        // slc:osgiBaseVersion
        public final static String SLC_MAJOR = "slc:major";