From: Bruno Sinou Date: Thu, 6 Mar 2014 19:13:04 +0000 (+0000) Subject: Work in progress - work on modular distributions. X-Git-Tag: argeo-slc-2.1.7~215 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=702f1e0c7d73edeb739dd62cd4248f489e1420b7;p=gpl%2Fargeo-slc.git Work in progress - work on modular distributions. git-svn-id: https://svn.argeo.org/slc/trunk@6886 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java index e5c91fcd9..e54b93434 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java @@ -50,16 +50,21 @@ public class DistImages { "icons/fetchRepo.png").createImage(); /* DISTRIBUTIONS */ + public final static Image IMG_WKSP_GROUP = DistPlugin.getImageDescriptor( + "icons/wkspGroup.gif").createImage(); public final static Image IMG_DISTGRP = DistPlugin.getImageDescriptor( "icons/distGrp.gif").createImage(); 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_GROUP_BASE = DistPlugin.getImageDescriptor( "icons/packages.gif").createImage(); - public final static Image IMG_WKSP_GROUP = DistPlugin.getImageDescriptor( - "icons/wkspGroup.gif").createImage(); /* CHECK BOXES */ public final static Image CHECKED = DistPlugin.getImageDescriptor( diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeWorkspace.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeWorkspace.java index f6f9d06fe..77cb08212 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeWorkspace.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeWorkspace.java @@ -36,6 +36,7 @@ import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.dist.DistPlugin; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.repo.ArtifactIndexer; +import org.argeo.slc.repo.DistributionBundleIndexer; import org.argeo.slc.repo.JarFileIndexer; import org.argeo.slc.repo.PdeSourcesIndexer; import org.argeo.slc.repo.RepoConstants; @@ -75,6 +76,8 @@ public class NormalizeWorkspace extends AbstractHandler implements SlcNames { private ArtifactIndexer artifactIndexer = new ArtifactIndexer(); private JarFileIndexer jarFileIndexer = new JarFileIndexer(); + private DistributionBundleIndexer distBundleIndexer = new DistributionBundleIndexer(); + private PdeSourcesIndexer pdeSourceIndexer = new PdeSourcesIndexer( artifactIndexer, jarFileIndexer); @@ -85,7 +88,8 @@ public class NormalizeWorkspace extends AbstractHandler implements SlcNames { Session currSession = null; NormalizeJob job; try { - String msg = "Your are about to normalize workspace: " + wkspName + String msg = "Your are about to normalize workspace: " + + wkspName + ".\nThis will index OSGi bundles and Maven artifacts, " + "it will also convert Maven sources to PDE Sources if needed.\n" + "Note that no information will be overwritten: " @@ -139,7 +143,8 @@ public class NormalizeWorkspace extends AbstractHandler implements SlcNames { + session.getWorkspace().getName(), expectedCount.intValue()); NormalizingTraverser tiv = new NormalizingTraverser(monitor); - session.getNode(artifactBasePath).accept(tiv); + Node artifactBaseNode =session.getNode(artifactBasePath); + artifactBaseNode.accept(tiv); } catch (Exception e) { return new Status(IStatus.ERROR, DistPlugin.ID, "Cannot normalize distribution " @@ -181,6 +186,7 @@ public class NormalizeWorkspace extends AbstractHandler implements SlcNames { monitor.subTask(node.getName()); artifactIndexer.index(node); jarFileIndexer.index(node); + distBundleIndexer.index(node); node.getSession().save(); monitor.worked(1); if (log.isDebugEnabled()) diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenWorkspaceEditor.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenWorkspaceEditor.java index db7155efa..c7734a8c4 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenWorkspaceEditor.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenWorkspaceEditor.java @@ -75,7 +75,6 @@ public class OpenWorkspaceEditor extends AbstractHandler { } finally { JcrUtils.logoutQuietly(defaultSession); } - } WorkspaceEditorInput wei = new WorkspaceEditorInput(repoNodePath, diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeComparator.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeComparator.java index d0c7066d1..c5b17e089 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeComparator.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeComparator.java @@ -1,6 +1,7 @@ package org.argeo.slc.client.ui.dist.controllers; import org.argeo.slc.client.ui.dist.model.DistParentElem; +import org.argeo.slc.client.ui.dist.model.ModularDistVersionElem; 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; @@ -43,7 +44,7 @@ public class DistTreeComparator extends ViewerComparator { s2 = e2.toString(); } - if (e1 instanceof WorkspaceElem) + if (e1 instanceof WorkspaceElem || e1 instanceof ModularDistVersionElem) // Reverse order for versions return s2.compareTo(s1); else diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeLabelProvider.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeLabelProvider.java index 4bebdda88..3fc3aca08 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeLabelProvider.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/controllers/DistTreeLabelProvider.java @@ -3,7 +3,8 @@ package org.argeo.slc.client.ui.dist.controllers; import org.argeo.eclipse.ui.jcr.JcrImages; import org.argeo.slc.client.ui.dist.DistImages; import org.argeo.slc.client.ui.dist.model.DistParentElem; -import org.argeo.slc.client.ui.dist.model.GroupBaseElem; +import org.argeo.slc.client.ui.dist.model.ModularDistBaseElem; +import org.argeo.slc.client.ui.dist.model.ModularDistVersionElem; 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; @@ -39,8 +40,12 @@ public class DistTreeLabelProvider extends ColumnLabelProvider { return JcrImages.WORKSPACE_DISCONNECTED; } else if (element instanceof WkspGroupElem) return DistImages.IMG_WKSP_GROUP; - else if (element instanceof GroupBaseElem) - return DistImages.IMG_GROUP_BASE; + // else if (element instanceof GroupBaseElem) + // return DistImages.IMG_GROUP_BASE; + else if (element instanceof ModularDistBaseElem) + return DistImages.IMG_MODULAR_DIST_BASE; + else if (element instanceof ModularDistVersionElem) + return DistImages.IMG_MODULAR_DIST_VERSION; return super.getImage(element); } } \ 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 new file mode 100644 index 000000000..04fee41ec --- /dev/null +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java @@ -0,0 +1,431 @@ +/* + * 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.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.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; + + // 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"; + + private Node moduleParent; + + 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 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_MODULE_CATEGORY); + DynamicOperand nameDO = factory.propertyValue( + source.getSelectorName(), SlcNames.SLC_MODULE_NAME); + DynamicOperand versionDO = factory.propertyValue( + source.getSelectorName(), SlcNames.SLC_MODULE_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 propertiesList = new ArrayList(); + List propertyTypesList = new ArrayList(); + + // 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(300); + col.getColumn().setText("Name"); + col.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return JcrUtils.get((Node) element, + DistConstants.SLC_BUNDLE_NAME); + } + }); + col.getColumn().addSelectionListener(getSelectionAdapter(0)); + propertiesList.add(DistConstants.SLC_BUNDLE_NAME); + propertyTypesList.add(PropertyType.STRING); + + // Symbolic name + col = new TableViewerColumn(viewer, SWT.V_SCROLL); + col.getColumn().setWidth(300); + col.getColumn().setText("Symbolic Name"); + col.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return JcrUtils.get((Node) element, SLC_SYMBOLIC_NAME); + } + }); + col.getColumn().addSelectionListener(getSelectionAdapter(1)); + propertiesList.add(SLC_SYMBOLIC_NAME); + propertyTypesList.add(PropertyType.STRING); + + // Version + col = new TableViewerColumn(viewer, SWT.NONE); + col.getColumn().setWidth(130); + col.getColumn().setText("Version"); + col.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return JcrUtils.get((Node) element, SLC_BUNDLE_VERSION); + } + }); + col.getColumn().addSelectionListener(getSelectionAdapter(2)); + propertiesList.add(SLC_BUNDLE_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 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) 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/model/ModularDistBaseElem.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java new file mode 100644 index 000000000..08c7d6d3e --- /dev/null +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java @@ -0,0 +1,103 @@ +package org.argeo.slc.client.ui.dist.model; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.query.QueryManager; +import javax.jcr.query.QueryResult; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.QueryObjectModelFactory; +import javax.jcr.query.qom.Selector; + +import org.argeo.ArgeoException; +import org.argeo.slc.SlcException; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +/** + * Abstract the base a given modular distribution set that is the parent all + * versions of the same distribution + */ +public class ModularDistBaseElem extends DistParentElem { + + final static public String AETHER_BINARIES_TYPE = "binaries"; + final static public String AETHER_DEP_TYPE = "dep"; + private String type; + private Node artifactBase; + + public ModularDistBaseElem(WorkspaceElem wkspElem, String name, + Node artifactBase, String type) { + super(name, wkspElem.inHome(), wkspElem.isReadOnly()); + setParent(wkspElem); + this.artifactBase = artifactBase; + this.type = type; + } + + /** + * Override normal behavior to initialize children only when first requested + */ + @Override + public synchronized boolean hasChildren() { + if (isLoaded()) { + return super.hasChildren(); + } else { + return true; + } + }; + + /** + * Override normal behavior to initialize children only when first requested + */ + @Override + public synchronized Object[] getChildren() { + if (isLoaded()) { + return super.getChildren(); + } else { + // initialize current object + try { + NodeIterator ni = getDistVersions(); + while (ni.hasNext()) { + Node curNode = ni.nextNode(); + addChild(new ModularDistVersionElem(this, curNode + .getProperty(SlcNames.SLC_ARTIFACT_VERSION) + .getString(), curNode)); + } + return super.getChildren(); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexcpected error while initializing children SingleJcrNode", + re); + } + } + } + + public NodeIterator getDistVersions() { + try { + QueryManager queryManager = artifactBase.getSession() + .getWorkspace().getQueryManager(); + QueryObjectModelFactory factory = queryManager.getQOMFactory(); + Selector source = factory.selector( + SlcTypes.SLC_MODULAR_DISTRIBUTION, + SlcTypes.SLC_MODULAR_DISTRIBUTION); + Constraint constraint = factory.descendantNode( + source.getSelectorName(), artifactBase.getPath()); + // Ordering order = factory.descending(factory.propertyValue( + // source.getSelectorName(), SlcNames.SLC_ARTIFACT_VERSION)); + // Ordering[] orderings = { order }; + QueryObjectModel query = factory.createQuery(source, constraint, + null, null); + QueryResult queryResult = query.execute(); + return queryResult.getNodes(); + } catch (RepositoryException e) { + throw new SlcException( + "Unable to version for modular distribution: " + getName(), + e); + } + } + + public String getType() { + return type; + } + +} \ 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/model/ModularDistVersionElem.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistVersionElem.java new file mode 100644 index 000000000..8199f6901 --- /dev/null +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistVersionElem.java @@ -0,0 +1,31 @@ +package org.argeo.slc.client.ui.dist.model; + +import javax.jcr.Node; + +/** + * Abstract a node of type slc:modularDistribution that has a child node that + * lists the modules contained in the current distribution + */ +public class ModularDistVersionElem extends DistParentElem { + private final Node modularDistVersionNode; + + public ModularDistVersionElem(ModularDistBaseElem modularDistGroupElem, + String version, Node modularDistVersionNode) { + super(version, modularDistGroupElem.inHome(), modularDistGroupElem + .isReadOnly()); + setParent(modularDistGroupElem); + this.modularDistVersionNode = modularDistVersionNode; + } + + public Object[] getChildren() { + return null; + } + + public String getLabel() { + return getName(); + } + + public Node getModularDistVersionNode() { + return modularDistVersionNode; + } +} \ 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/model/WorkspaceElem.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/WorkspaceElem.java index 7cdccfc7a..41ba6efe3 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/WorkspaceElem.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/WorkspaceElem.java @@ -1,5 +1,6 @@ package org.argeo.slc.client.ui.dist.model; +import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -14,7 +15,7 @@ import org.argeo.slc.jcr.SlcTypes; public class WorkspaceElem extends DistParentElem { private final RepoElem repoElem; private String workspaceName; - private Session defaultSession; + private Session currSession; public WorkspaceElem(WkspGroupElem parent, RepoElem repoElem, String workspaceName) { @@ -33,20 +34,20 @@ public class WorkspaceElem extends DistParentElem { } public Boolean isConnected() { - if (defaultSession != null && defaultSession.isLive()) + if (currSession != null && currSession.isLive()) return true; else return false; } public void login() { - defaultSession = repoElem.repositoryLogin(getName()); + currSession = repoElem.repositoryLogin(getName()); } public boolean hasChildren() { try { if (isConnected()) - return defaultSession.getRootNode().hasNodes(); + return currSession.getRootNode().hasNodes(); else return false; } catch (RepositoryException re) { @@ -64,23 +65,44 @@ public class WorkspaceElem extends DistParentElem { } else { // initialize current object try { - if (defaultSession == null) + if (currSession == null) return null; else { - Query groupQuery = defaultSession - .getWorkspace() + Query groupQuery = currSession.getWorkspace() .getQueryManager() + // .createQuery( + // "select * from [" + SlcTypes.SLC_GROUP_BASE + // + "] as group order by group.[" + // + SlcNames.SLC_GROUP_BASE_ID + "]", .createQuery( - "select * from [" + SlcTypes.SLC_GROUP_BASE - + "] as group order by group.[" - + SlcNames.SLC_GROUP_BASE_ID + "]", - Query.JCR_SQL2); - NodeIterator groups = groupQuery.execute().getNodes(); - while (groups.hasNext()) { - addChild(new GroupBaseElem(WorkspaceElem.this, groups - .nextNode() - .getProperty(SlcNames.SLC_GROUP_BASE_ID) - .getString())); + "select * from [" + + SlcTypes.SLC_MODULAR_DISTRIBUTION + + "]", Query.JCR_SQL2); + NodeIterator distributions = groupQuery.execute() + .getNodes(); + distribs: while (distributions.hasNext()) { + Node currDist = distributions.nextNode(); + Node distBase = currDist.getParent().getParent(); + if (!distBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) + continue distribs; + String groupId = distBase.getProperty( + SlcNames.SLC_GROUP_ID).getString(); + String artifactId = distBase.getProperty( + SlcNames.SLC_ARTIFACT_ID).getString(); + + String name; + String type; + if (ModularDistBaseElem.AETHER_BINARIES_TYPE + .equals(artifactId)) { + name = groupId; + type = ModularDistBaseElem.AETHER_BINARIES_TYPE; + } else { + name = artifactId; + type = ModularDistBaseElem.AETHER_DEP_TYPE; + } + if (getChildByName(name) == null) + addChild(new ModularDistBaseElem( + WorkspaceElem.this, name, distBase, type)); } } return super.getChildren(); @@ -91,10 +113,10 @@ public class WorkspaceElem extends DistParentElem { } } } - + @Override public synchronized void dispose() { - JcrUtils.logoutQuietly(defaultSession); + JcrUtils.logoutQuietly(currSession); super.dispose(); } } diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/DistributionBundleIndexer.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/DistributionBundleIndexer.java new file mode 100644 index 000000000..7441490bc --- /dev/null +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/DistributionBundleIndexer.java @@ -0,0 +1,288 @@ +package org.argeo.slc.repo; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; + +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.aether.AetherUtils; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; +import org.osgi.framework.Constants; +import org.sonatype.aether.artifact.Artifact; + +/** + * Index distribution bundles that is mainly dep artifacts that have generate a + * modular distribution csv index during maven build + */ +public class DistributionBundleIndexer implements NodeIndexer { + private final static Log log = LogFactory + .getLog(DistributionBundleIndexer.class); + + private final static String INDEX_FILE_NAME = "modularDistribution.csv"; + + // private final String url; + + private Manifest manifest; + private String symbolicName; + private String version; + + /** can be null */ + // private String baseUrl; + /** can be null */ + // private String relativeUrl; + + private List artifacts; + + private String separator = ","; + + // public DistributionBundleIndexer(String url) { + // this.url = url; + // } + // + // public DistributionBundleIndexer(String baseUrl, String relativeUrl) { + // if (baseUrl == null || !baseUrl.endsWith("/")) + // throw new SlcException("Base url " + baseUrl + " badly formatted"); + // if (relativeUrl.startsWith("http") || relativeUrl.startsWith("file:")) + // throw new SlcException("Relative URL " + relativeUrl + // + " badly formatted"); + // this.url = baseUrl + relativeUrl; + // this.baseUrl = baseUrl; + // this.relativeUrl = relativeUrl; + // } + + public Boolean support(String path) { + return FilenameUtils.getExtension(path).equals("jar"); + } + + public void index(Node fileNode) { + JarInputStream jarIn = null; + Binary fileBinary = null; + try { + if (!support(fileNode.getPath())) + return; + + if (!fileNode.isNodeType(NodeType.NT_FILE)) + return; + + Session jcrSession = fileNode.getSession(); + Node contentNode = fileNode.getNode(Node.JCR_CONTENT); + fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary(); + jarIn = new JarInputStream(fileBinary.getStream()); + + // meta data + manifest = jarIn.getManifest(); + if (manifest == null) { + log.error(fileNode + " has no MANIFEST"); + return; + } + symbolicName = manifest.getMainAttributes().getValue( + Constants.BUNDLE_SYMBOLICNAME); + version = manifest.getMainAttributes().getValue( + Constants.BUNDLE_VERSION); + + JarEntry indexEntry; + while ((indexEntry = jarIn.getNextJarEntry()) != null) { + String entryName = indexEntry.getName(); + if (entryName.equals(INDEX_FILE_NAME)) { + break; + } + jarIn.closeEntry(); + } + + // list artifacts + if (indexEntry == null) + return; // Not a modular definition artifact + + // throw new SlcException("No index " + INDEX_FILE_NAME + " in " + // + fileNode.getPath()); + // + + artifacts = listArtifacts(jarIn); + + if (artifacts == null || artifacts.isEmpty()) + return; // no modules found + else { + Node modules; + if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION)) { + modules = fileNode.getNode(SlcNames.SLC_MODULES); + } else { + fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION); + modules = JcrUtils.mkdirs(fileNode, SlcNames.SLC_MODULES, + NodeType.NT_UNSTRUCTURED); + } + + for (Artifact artifact : artifacts) { + // TODO clean this once an overwrite policy has been + // decided. + if (!modules.hasNode(artifact.getArtifactId())) { + Node moduleCoord = modules.addNode( + artifact.getArtifactId(), + SlcTypes.SLC_MODULE_COORDINATES); + moduleCoord.setProperty(SlcNames.SLC_MODULE_NAME, + artifact.getArtifactId()); + moduleCoord.setProperty(SlcNames.SLC_MODULE_VERSION, + artifact.getVersion()); + String groupId = artifact.getGroupId(); + if (groupId != null && !"".equals(groupId.trim())) + moduleCoord.setProperty( + SlcNames.SLC_MODULE_CATEGORY, + artifact.getGroupId()); + } + } + + } + + jarIn.closeEntry(); + + // find base URL + // won't work if distribution artifact is not listed + // for (int i = 0; i < artifacts.size(); i++) { + // OsgiArtifact osgiArtifact = artifacts.get(i); + // if (osgiArtifact.getSymbolicName().equals(symbolicName) + // && osgiArtifact.getVersion().equals(version)) { + // String relativeUrl = osgiArtifact.getRelativeUrl(); + // if (url.endsWith(relativeUrl)) { + // baseUrl = url.substring(0, url.length() + // - osgiArtifact.getRelativeUrl().length()); + // break; + // } + // } + // } + } catch (Exception e) { + throw new SlcException("Cannot list dependencies from " + fileNode, + e); + } finally { + if (jarIn != null) + try { + jarIn.close(); + } catch (IOException e) { + // silent + } + } + } + + protected List listArtifacts(InputStream in) { + List artifacts = new ArrayList(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(in)); + String line = null; + while ((line = reader.readLine()) != null) { + + StringTokenizer st = new StringTokenizer(line, separator); + String moduleName = st.nextToken(); + String moduleVersion = st.nextToken(); + String relativeUrl = st.nextToken(); + + // + // String Category = getCategoryFromRelativeUrl(relativeUrl, + // moduleName); + + artifacts.add(AetherUtils.convertPathToArtifact(relativeUrl, + null)); + + if (log.isTraceEnabled()) + log.debug("Processed dependency: " + line); + } + } catch (Exception e) { + throw new SlcException("Cannot list artifacts", e); + } + return artifacts; + } + + /** Relative path to the directories where the files will be stored */ + private String getCategoryFromRelativeUrl(String relativeUrl, + String moduleName) { + int index = relativeUrl.indexOf("moduleName"); + if (index < 1) + throw new SlcException("Unvalid relative URL: " + relativeUrl + + " for module " + moduleName); + // Remove trailing / + String result = relativeUrl.substring(0, index - 1); + return result.replace('/', '.'); + } + + /** + * List full URLs of the bundles, based on base URL, usable directly for + * download. + */ + // public List/* */listUrls() { + // if (baseUrl == null) + // throw new SlcException("Base URL is not set"); + // + // if (artifacts == null) + // throw new SlcException("Artifact list not initialized"); + // + // List/* */urls = new ArrayList(); + // for (int i = 0; i < artifacts.size(); i++) { + // OsgiArtifact osgiArtifact = (OsgiArtifact) artifacts.get(i); + // urls.add(baseUrl + osgiArtifact.getRelativeUrl()); + // } + // return urls; + // } + // + // public void setBaseUrl(String baseUrl) { + // this.baseUrl = baseUrl; + // } + + /** Separator used to parse the tabular file, default is "," */ + public void setSeparator(String modulesUrlSeparator) { + this.separator = modulesUrlSeparator; + } + + // public String getRelativeUrl() { + // return relativeUrl; + // } + + /** One of the listed artifact */ + protected static class OsgiArtifact { + private final String category; + private final String symbolicName; + private final String version; + private final String relativeUrl; + + public OsgiArtifact(String category, String symbolicName, + String version, String relativeUrl) { + super(); + this.category = category; + this.symbolicName = symbolicName; + this.version = version; + this.relativeUrl = relativeUrl; + } + + public String getCategory() { + return category; + } + + public String getSymbolicName() { + return symbolicName; + } + + public String getVersion() { + return version; + } + + public String getRelativeUrl() { + return relativeUrl; + } + + } +} diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java index 8d0147ec0..18e864928 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java @@ -262,78 +262,80 @@ public class RepoSync implements Runnable { protected void syncNode(Node sourceNode, Session targetSession) throws RepositoryException, SAXException { // Boolean singleLevel = singleLevel(sourceNode); + try { + if (monitor != null && monitor.isCanceled()) { + updateMonitor("Fetched has been canceled, " + + "process is terminating"); + return; + } - if (monitor != null && monitor.isCanceled()) { - updateMonitor("Fetched has been canceled, " - + "process is terminating"); - return; - } - - Node targetParentNode = targetSession.getNode(sourceNode.getParent() - .getPath()); - Node targetNode; - if (monitor != null - && sourceNode.isNodeType(NodeType.NT_HIERARCHY_NODE)) - monitor.subTask("Process " + sourceNode.getPath()); - - final Boolean isNew; - if (!targetSession.itemExists(sourceNode.getPath())) { - isNew = true; - targetNode = targetParentNode.addNode(sourceNode.getName(), - sourceNode.getPrimaryNodeType().getName()); - } else { - isNew = false; - targetNode = targetSession.getNode(sourceNode.getPath()); - if (!targetNode.getPrimaryNodeType().getName() - .equals(sourceNode.getPrimaryNodeType().getName())) - targetNode.setPrimaryType(sourceNode.getPrimaryNodeType() - .getName()); - } + Node targetParentNode = targetSession.getNode(sourceNode + .getParent().getPath()); + Node targetNode; + if (monitor != null + && sourceNode.isNodeType(NodeType.NT_HIERARCHY_NODE)) + monitor.subTask("Process " + sourceNode.getPath()); + + final Boolean isNew; + if (!targetSession.itemExists(sourceNode.getPath())) { + isNew = true; + targetNode = targetParentNode.addNode(sourceNode.getName(), + sourceNode.getPrimaryNodeType().getName()); + } else { + isNew = false; + targetNode = targetSession.getNode(sourceNode.getPath()); + if (!targetNode.getPrimaryNodeType().getName() + .equals(sourceNode.getPrimaryNodeType().getName())) + targetNode.setPrimaryType(sourceNode.getPrimaryNodeType() + .getName()); + } - // export - // sourceNode.getSession().exportSystemView(sourceNode.getPath(), - // contentHandler, false, singleLevel); - - // if (singleLevel) { - // if (targetSession.hasPendingChanges()) { - // // updateMonitor( - // // (isNew ? "Added " : "Updated ") + targetNode.getPath(), - // // true); - // if (doSave) - // targetSession.save(); - // } else { - // // updateMonitor("Checked " + targetNode.getPath(), false); - // } - // } - - // mixin and properties - for (NodeType nt : sourceNode.getMixinNodeTypes()) { - if (!targetNode.isNodeType(nt.getName()) - && targetNode.canAddMixin(nt.getName())) - targetNode.addMixin(nt.getName()); - } - copyProperties(sourceNode, targetNode); + // export + // sourceNode.getSession().exportSystemView(sourceNode.getPath(), + // contentHandler, false, singleLevel); + + // if (singleLevel) { + // if (targetSession.hasPendingChanges()) { + // // updateMonitor( + // // (isNew ? "Added " : "Updated ") + targetNode.getPath(), + // // true); + // if (doSave) + // targetSession.save(); + // } else { + // // updateMonitor("Checked " + targetNode.getPath(), false); + // } + // } + + // mixin and properties + for (NodeType nt : sourceNode.getMixinNodeTypes()) { + if (!targetNode.isNodeType(nt.getName()) + && targetNode.canAddMixin(nt.getName())) + targetNode.addMixin(nt.getName()); + } + copyProperties(sourceNode, targetNode); - // next level - for (NodeIterator ni = sourceNode.getNodes(); ni.hasNext();) { - Node sourceChild = ni.nextNode(); - syncNode(sourceChild, targetSession); - } + // next level + for (NodeIterator ni = sourceNode.getNodes(); ni.hasNext();) { + Node sourceChild = ni.nextNode(); + syncNode(sourceChild, targetSession); + } - copyTimestamps(sourceNode, targetNode); + copyTimestamps(sourceNode, targetNode); - if (sourceNode.isNodeType(NodeType.NT_HIERARCHY_NODE)) { - if (targetSession.hasPendingChanges()) { - if (sourceNode.isNodeType(NodeType.NT_FILE)) - updateMonitor( - (isNew ? "Added " : "Updated ") - + targetNode.getPath(), true); - // if (doSave) - targetSession.save(); - } else { - if (sourceNode.isNodeType(NodeType.NT_FILE)) - updateMonitor("Checked " + targetNode.getPath(), false); + if (sourceNode.isNodeType(NodeType.NT_HIERARCHY_NODE)) { + if (targetSession.hasPendingChanges()) { + if (sourceNode.isNodeType(NodeType.NT_FILE)) + updateMonitor((isNew ? "Added " : "Updated ") + + targetNode.getPath(), true); + // if (doSave) + targetSession.save(); + } else { + if (sourceNode.isNodeType(NodeType.NT_FILE)) + updateMonitor("Checked " + targetNode.getPath(), false); + } } + } catch (RepositoryException e) { + throw new SlcException("Cannot sync source node " + sourceNode, e); } } diff --git a/runtime/org.argeo.slc.repo/src/main/resources/org/argeo/slc/repo/repo.cnd b/runtime/org.argeo.slc.repo/src/main/resources/org/argeo/slc/repo/repo.cnd index c0bd68171..798046887 100644 --- a/runtime/org.argeo.slc.repo/src/main/resources/org/argeo/slc/repo/repo.cnd +++ b/runtime/org.argeo.slc.repo/src/main/resources/org/argeo/slc/repo/repo.cnd @@ -30,6 +30,16 @@ mixin mixin + slc:artifactVersions (argeo:references) m +[slc:modularDistribution] +mixin ++ slc:modules (nt:unstructured) m + +[slc:moduleCoordinates] > nt:unstructured +- slc:category (STRING) +- slc:name (STRING) +- slc:version (STRING) + + // ORIGINS [slc:knownOrigin] > nt:base mixin diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java index a728700ed..a68144a25 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java @@ -115,6 +115,14 @@ public interface SlcNames { // slc:exportedPackage public final static String SLC_USES = "slc:uses"; + // slc:modularDistribution + public final static String SLC_MODULES = "slc:modules"; + + // slc:moduleCoordinates + public final static String SLC_MODULE_CATEGORY = "slc:category"; + public final static String SLC_MODULE_NAME = "slc:name"; + public final static String SLC_MODULE_VERSION = "slc:version"; + // RPM // slc:rpm public final static String SLC_RPM_VERSION = "slc:rpmVersion"; diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java index d53494cef..0d647af8d 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java @@ -64,6 +64,9 @@ public interface SlcTypes { public final static String SLC_DYNAMIC_IMPORTED_PACKAGE = "slc:dynamicImportedPackage"; public final static String SLC_REQUIRED_BUNDLE = "slc:requiredBundle"; public final static String SLC_FRAGMENT_HOST = "slc:fragmentHost"; + + public final static String SLC_MODULAR_DISTRIBUTION = "slc:modularDistribution"; + public final static String SLC_MODULE_COORDINATES = "slc:moduleCoordinates"; // origin public final static String SLC_KNOWN_ORIGIN = "slc:knownOrigin";