X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=plugins%2Forg.argeo.slc.client.ui.dist%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fclient%2Fui%2Fdist%2Fviews%2FDistributionsView.java;h=29a1ca9c57b988b20c448e24405d7cdeee1d1969;hb=c2c5b6a8b8d57ec3a4b37a355b9fbd03c2dd653a;hp=6ac3d79ad783f5c90c4dea819217122746eb87a9;hpb=651d33e13bfa9a7b46464be412023ee747e612e8;p=gpl%2Fargeo-slc.git diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java index 6ac3d79ad..29a1ca9c5 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java @@ -15,19 +15,36 @@ */ package org.argeo.slc.client.ui.dist.views; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.jcr.Credentials; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.eclipse.ui.AbstractTreeContentProvider; +import org.argeo.ArgeoMonitor; +import org.argeo.eclipse.ui.EclipseArgeoMonitor; import org.argeo.eclipse.ui.ErrorFeedback; import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ArgeoJcrUtils; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.dist.DistPlugin; +import org.argeo.slc.client.ui.dist.DistUiUtils; import org.argeo.slc.client.ui.dist.commands.CopyWorkspace; import org.argeo.slc.client.ui.dist.commands.CreateWorkspace; import org.argeo.slc.client.ui.dist.commands.DeleteWorkspace; @@ -37,16 +54,32 @@ import org.argeo.slc.client.ui.dist.editors.DistributionEditor; import org.argeo.slc.client.ui.dist.editors.DistributionEditorInput; import org.argeo.slc.client.ui.dist.utils.CommandHelpers; import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.repo.RepoConstants; +import org.argeo.util.security.Keyring; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSourceAdapter; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; @@ -58,12 +91,13 @@ import org.eclipse.ui.part.ViewPart; * Browse and manipulate distributions (like merge, rename, etc.). Only support * one single repository currently. */ - -public class DistributionsView extends ViewPart implements SlcNames { +public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames { private final static Log log = LogFactory.getLog(DistributionsView.class); public final static String ID = DistPlugin.ID + ".distributionsView"; - private Repository repository; + private Repository nodeRepository; + private RepositoryFactory repositoryFactory; + private Keyring keyring; private TreeViewer viewer; @@ -75,21 +109,29 @@ public class DistributionsView extends ViewPart implements SlcNames { TreeViewerColumn col = new TreeViewerColumn(viewer, SWT.NONE); col.getColumn().setWidth(200); - col.getColumn().setText("Workspace"); + // col.getColumn().setText("Workspace"); col.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { + if (element instanceof RepoElem) + return ((RepoElem) element).getLabel(); return element.toString(); } }); final Tree table = viewer.getTree(); - table.setHeaderVisible(true); - table.setLinesVisible(true); + table.setHeaderVisible(false); + table.setLinesVisible(false); viewer.setContentProvider(new DistributionsContentProvider()); viewer.addDoubleClickListener(new DistributionsDCL()); + // Drag'n drop + Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; + int operations = DND.DROP_COPY | DND.DROP_MOVE; + viewer.addDragSupport(operations, tt, new ViewDragListener()); + viewer.addDropSupport(operations, tt, new ViewDropListener(viewer)); + MenuManager menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(viewer.getTree()); menuManager.addMenuListener(new IMenuListener() { @@ -100,24 +142,38 @@ public class DistributionsView extends ViewPart implements SlcNames { viewer.getTree().setMenu(menu); getSite().registerContextMenu(menuManager, viewer); - viewer.setInput(getSite()); - - } - - @Override - public void setFocus() { - viewer.getTree().setFocus(); - } + Session nodeSession = null; + try { + nodeSession = nodeRepository.login(); + + // make sure base directory is available + Node repos = JcrUtils.mkdirs(nodeSession, + UserJcrUtils.getUserHome(nodeSession).getPath() + + RepoConstants.REPOSITORIES_BASE_PATH); + nodeSession.save(); + + // register default local java repository + String alias = RepoConstants.DEFAULT_JAVA_REPOSITORY_ALIAS; + Repository javaRepository = ArgeoJcrUtils.getRepositoryByAlias( + repositoryFactory, alias); + if (javaRepository != null) { + if (!repos.hasNode(alias)) { + Node repoNode = repos.addNode(alias, + ArgeoTypes.ARGEO_REMOTE_REPOSITORY); + repoNode.setProperty(ARGEO_URI, alias); + repoNode.addMixin(NodeType.MIX_TITLE); + repoNode.setProperty(Property.JCR_TITLE, "vm://" + alias); + nodeSession.save(); + } + } + } catch (RepositoryException e) { + throw new SlcException("Cannot register repository", e); + } finally { + JcrUtils.logoutQuietly(nodeSession); + } - /** - * Force refresh of the whole view - */ - public void refresh() { - viewer.setContentProvider(new DistributionsContentProvider()); - } + viewer.setInput(nodeRepository); - public void setRepository(Repository repository) { - this.repository = repository; } /** Programatically configure the context menu */ @@ -146,8 +202,7 @@ public class DistributionsView extends ViewPart implements SlcNames { // create workspace CommandHelpers.refreshCommand(menuManager, window, CreateWorkspace.ID, CreateWorkspace.DEFAULT_LABEL, - CreateWorkspace.DEFAULT_ICON_PATH, - tp instanceof RepositoryElem); + CreateWorkspace.DEFAULT_ICON_PATH, !isDistribElem); // Normalize workspace Map params = new HashMap(); @@ -182,67 +237,393 @@ public class DistributionsView extends ViewPart implements SlcNames { } } - private class DistributionsContentProvider extends - AbstractTreeContentProvider { + @Override + public void setFocus() { + viewer.getTree().setFocus(); + } + + /* + * DEPENDENCY INJECTION + */ + /** + * Force refresh of the whole view + */ + public void refresh() { + viewer.setContentProvider(new DistributionsContentProvider()); + } + + public void setNodeRepository(Repository repository) { + this.nodeRepository = repository; + } + + public void setRepositoryFactory(RepositoryFactory repositoryFactory) { + this.repositoryFactory = repositoryFactory; + } + + public void setKeyring(Keyring keyring) { + this.keyring = keyring; + } + + /* + * INTERNAL CLASSES + */ + /** Content provider */ + private class DistributionsContentProvider implements ITreeContentProvider { + Session nodeSession; + List repositories = new ArrayList(); + + public Object[] getElements(Object input) { + Repository nodeRepository = (Repository) input; + try { + if (nodeSession != null) + dispose(); + nodeSession = nodeRepository.login(); + + String reposPath = UserJcrUtils.getUserHome(nodeSession) + .getPath() + RepoConstants.REPOSITORIES_BASE_PATH; + NodeIterator repos = nodeSession.getNode(reposPath).getNodes(); + while (repos.hasNext()) { + Node repoNode = repos.nextNode(); + if (repoNode.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) { + repositories.add(new RepoElem(repoNode)); + } + } + } catch (RepositoryException e) { + throw new SlcException("Cannot get base elements", e); + } + return repositories.toArray(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof RepoElem) { + return ((RepoElem) parentElement).getChildren(); + } else if (parentElement instanceof DistributionElem) { + return ((DistributionElem) parentElement).getChildren(); + } + return null; + } + + public Object getParent(Object element) { + // TODO register repo elem in distirbution elem? + return null; + } - public Object[] getElements(Object arg0) { - return new Object[] { new RepositoryElem("java", repository) }; + public boolean hasChildren(Object element) { + if (element instanceof RepoElem) { + return true; + } else if (element instanceof DistributionElem) { + return false; + } + return false; + } + + public void dispose() { + for (RepoElem repoElem : repositories) + repoElem.dispose(); + repositories = new ArrayList(); + JcrUtils.logoutQuietly(nodeSession); } } - private static class RepositoryElem extends TreeParent { - // private final Repository repository; - private Session defaultSession; + /** A software repository */ + private class RepoElem { + private Node repoNode; + + private Repository repository; + private Credentials credentials; - public RepositoryElem(String name, Repository repository) { - super(name); - // this.repository = repository; + public RepoElem(Node repoNode) { + this.repoNode = repoNode; + } + + /** Lazily connects to repository */ + protected void connect() { + if (repository != null) + return; + repository = DistUiUtils.getRepository(repositoryFactory, keyring, + repoNode); + credentials = DistUiUtils.getRepositoryCredentials(keyring, + repoNode); + } + + public String getLabel() { try { - defaultSession = repository.login(); - String[] workspaceNames = defaultSession.getWorkspace() + if (repoNode.isNodeType(NodeType.MIX_TITLE)) { + return repoNode.getProperty(Property.JCR_TITLE).getString(); + } else { + return repoNode.getName(); + } + } catch (RepositoryException e) { + throw new SlcException("Cannot read label of " + repoNode, e); + } + } + + public String toString() { + return repoNode.toString(); + } + + public Object[] getChildren() { + connect(); + Session session = null; + try { + session = repository.login(credentials); + String[] workspaceNames = session.getWorkspace() .getAccessibleWorkspaceNames(); + List distributionElems = new ArrayList(); for (String workspace : workspaceNames) - addChild(new DistributionElem(repository, workspace)); + distributionElems.add(new DistributionElem(this, workspace, + credentials)); + // FIXME remove deleted workspaces + return distributionElems.toArray(); } catch (RepositoryException e) { - ErrorFeedback.show("Cannot log to repository", e); + throw new SlcException( + "Cannot list workspaces for " + repoNode, e); + } finally { + JcrUtils.logoutQuietly(session); } } - @Override - public synchronized void dispose() { - if (log.isTraceEnabled()) - log.trace("Disposing RepositoryElement"); - if (defaultSession != null) - defaultSession.logout(); - super.dispose(); + public void dispose() { + } + + public Node getRepoNode() { + return repoNode; + } + + public String getRepoPath() { + try { + return repoNode.getPath(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get path for " + repoNode, e); + } + } + + public Repository getRepository() { + connect(); + return repository; } } + /** Abstracts a distribution, that is a workspace */ private static class DistributionElem extends TreeParent { + private final RepoElem repoElem; + private final Node workspaceNode; private final String workspaceName; - private final Repository repository; + private final Credentials credentials; - public DistributionElem(Repository repository, String workspaceName) { + public DistributionElem(RepoElem repoElem, String workspaceName, + Credentials credentials) { super(workspaceName); + this.repoElem = repoElem; + try { + // TODO move it to repo elem + this.workspaceNode = repoElem.getRepoNode().hasNode( + workspaceName) ? repoElem.getRepoNode().getNode( + workspaceName) : repoElem.getRepoNode().addNode( + workspaceName); + repoElem.getRepoNode().getSession().save(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get or add workspace node " + + workspaceName, e); + } this.workspaceName = workspaceName; - this.repository = repository; + this.credentials = credentials; + } + + public Node getWorkspaceNode() { + return workspaceNode; } public String getWorkspaceName() { return workspaceName; } - public Repository getRepository() { - return repository; + public String getWorkspacePath() { + try { + return workspaceNode.getPath(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get or add workspace path " + + workspaceName, e); + } + } + + public String getRepoPath() { + try { + return workspaceNode.getParent().getPath(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get or add workspace path " + + workspaceName, e); + } + } + + public RepoElem getRepoElem() { + return repoElem; + } + + public Credentials getCredentials() { + return credentials; } } - @Override - public void dispose() { - super.dispose(); + /** Listens to drag */ + class ViewDragListener extends DragSourceAdapter { + public void dragSetData(DragSourceEvent event) { + IStructuredSelection selection = (IStructuredSelection) viewer + .getSelection(); + if (selection.getFirstElement() instanceof DistributionElem) { + DistributionElem de = (DistributionElem) selection + .getFirstElement(); + if (TextTransfer.getInstance().isSupportedType(event.dataType)) { + event.data = de.getWorkspacePath(); + if (log.isDebugEnabled()) + log.debug("Distribution drag for " + event.data); + } + } + } } + /** Listens to drop */ + class ViewDropListener extends ViewerDropAdapter { + + public ViewDropListener(Viewer viewer) { + super(viewer); + } + + @Override + public boolean performDrop(Object data) { + DistributionElem sourceDist = (DistributionElem) getSelectedObject(); + RepoElem targetRepo = (RepoElem) getCurrentTarget(); + + Boolean ok = MessageDialog.openConfirm(getSite().getShell(), + "Confirm distribution merge", "Do you want to merge " + + sourceDist.getWorkspaceName() + " (from repo " + + sourceDist.getRepoElem().getLabel() + + ") to repo " + targetRepo.getLabel() + "?"); + if (!ok) + return false; + + try { + String sourceWorkspace = sourceDist.getWorkspaceName(); + Repository sourceRepository = DistUiUtils.getRepository( + repositoryFactory, keyring, sourceDist + .getWorkspaceNode().getParent()); + Credentials sourceCredentials = DistUiUtils + .getRepositoryCredentials(keyring, sourceDist + .getWorkspaceNode().getParent()); + + String targetWorkspace = sourceWorkspace; + Repository targetRepository = DistUiUtils.getRepository( + repositoryFactory, keyring, targetRepo.getRepoNode()); + Credentials targetCredentials = DistUiUtils + .getRepositoryCredentials(keyring, + targetRepo.getRepoNode()); + + // Open sessions here since the background thread + // won't necessarily be authenticated. + // Job should close the sessions. + Session sourceSession = sourceRepository.login( + sourceCredentials, sourceWorkspace); + Session targetSession; + try { + targetSession = targetRepository.login(targetCredentials, + targetWorkspace); + } catch (NoSuchWorkspaceException e) { + Session defaultSession = targetRepository + .login(targetCredentials); + try { + defaultSession.getWorkspace().createWorkspace( + targetWorkspace); + } catch (Exception e1) { + throw new SlcException("Cannot create new workspace " + + targetWorkspace, e); + } finally { + JcrUtils.logoutQuietly(defaultSession); + } + targetSession = targetRepository.login(targetCredentials, + targetWorkspace); + } + + Job workspaceMergeJob = new WorkspaceMergeJob(sourceSession, + targetSession); + workspaceMergeJob.setUser(true); + workspaceMergeJob.schedule(); + return true; + } catch (RepositoryException e) { + throw new SlcException("Cannot process drop from " + sourceDist + + " to " + targetRepo, e); + } + } + + @Override + public boolean validateDrop(Object target, int operation, + TransferData transferType) { + if (target instanceof RepoElem) { + if (getSelectedObject() instanceof DistributionElem) { + // check if not same repository + String srcRepoPath = ((DistributionElem) getSelectedObject()) + .getRepoPath(); + String targetRepoPath = ((RepoElem) target).getRepoPath(); + return !targetRepoPath.equals(srcRepoPath); + } + } + return false; + } + } + + private static class WorkspaceMergeJob extends Job { + private Session sourceSession; + private Session targetSession; + + public WorkspaceMergeJob(Session sourceSession, Session targetSession) { + super("Workspace merge"); + this.sourceSession = sourceSession; + this.targetSession = targetSession; + } + + @Override + protected IStatus run(IProgressMonitor eclipseMonitor) { + long begin = System.currentTimeMillis(); + try { + // Not implemented in Davex Jackrabbit v2.2 + // Query countQuery = sourceSession + // .getWorkspace() + // .getQueryManager() + // .createQuery("select count(*) from [nt:file]", + // Query.JCR_SQL2); + // QueryResult result = countQuery.execute(); + // Long fileCount = result.getRows().nextRow().getValues()[0] + // .getLong(); + + ArgeoMonitor monitor = new EclipseArgeoMonitor(eclipseMonitor); + eclipseMonitor.beginTask("Copy files", ArgeoMonitor.UNKNOWN); + + Long count = JcrUtils.copyFiles(sourceSession.getRootNode(), + targetSession.getRootNode(), true, monitor); + + monitor.done(); + long duration = (System.currentTimeMillis() - begin) / 1000;// in + // s + if (log.isDebugEnabled()) + log.debug("Copied " + count + " files in " + + (duration / 60) + "min " + (duration % 60) + "s"); + + return Status.OK_STATUS; + } catch (RepositoryException e) { + return new Status(IStatus.ERROR, DistPlugin.ID, "Cannot merge", + e); + } finally { + JcrUtils.logoutQuietly(sourceSession); + JcrUtils.logoutQuietly(targetSession); + } + } + } + + /** Listen to double-clicks */ private class DistributionsDCL implements IDoubleClickListener { public void doubleClick(DoubleClickEvent event) { @@ -253,8 +634,10 @@ public class DistributionsView extends ViewPart implements SlcNames { if (obj instanceof DistributionElem) { DistributionElem distributionElem = (DistributionElem) obj; DistributionEditorInput dei = new DistributionEditorInput( - distributionElem.getRepository(), - distributionElem.getWorkspaceName()); + distributionElem.getName(), distributionElem + .getRepoElem().getRepository(), + distributionElem.getWorkspaceName(), + distributionElem.getCredentials()); try { DistPlugin.getDefault().getWorkbench() .getActiveWorkbenchWindow().getActivePage() @@ -266,4 +649,72 @@ public class DistributionsView extends ViewPart implements SlcNames { } } } + + // + // try { + // nodeSession = nodeRepository.login(); + // NodeIterator repos = JcrUtils.mkdirs( + // nodeSession, + // UserJcrUtils.getUserHome(nodeSession).getPath() + // + RepoConstants.REPOSITORIES_BASE_PATH).getNodes(); + // while (repos.hasNext()) { + // Node repository = repos.nextNode(); + // String label = null; + // if (repository.isNodeType(NodeType.MIX_TITLE)) { + // label = repository.getProperty(Property.JCR_TITLE) + // .getString(); + // } + // + // if (repository.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) { + // String uri = repository.getProperty(ARGEO_URI).getString(); + // Credentials credentials = null; + // if (repository.hasProperty(ARGEO_USER_ID)) { + // String userId = repository.getProperty(ARGEO_USER_ID) + // .getString(); + // credentials = new SimpleCredentials(userId, + // "".toCharArray()); + // } + // Repository remoteRepository = ArgeoJcrUtils + // .getRepositoryByUri(repositoryFactory, uri); + // if (label == null) + // label = repository.getName(); + // repositories.add(new RepositoryElem(label, + // remoteRepository, credentials)); + // } + // } + // } catch (RepositoryException e) { + // throw new ArgeoException("Cannot read registered repositories", e); + // } + + // Remote + // String uri = null; + // Credentials credentials = null; + // Repository remoteRepository = null; + + // try { + // uri = "http://dev.argeo.org/org.argeo.jcr.webapp/pub/java"; + // credentials = new GuestCredentials(); + // remoteRepository = + // ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, uri); + // repositories.add(new RepositoryElem("anonymous@dev.argeo.org//java", + // remoteRepository, credentials)); + // } catch (Exception e) { + // e.printStackTrace(); + // } + + // uri = "http://localhost:7070/org.argeo.jcr.webapp/pub/java"; + // credentials = new GuestCredentials(); + // remoteRepository = + // ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, uri); + // repositories.add(new RepositoryElem("anonymous@localhost//java", + // remoteRepository, credentials)); + + // uri = "http://localhost:7070/org.argeo.jcr.webapp/remoting/java"; + // credentials = new SimpleCredentials(System.getProperty("user.name"), + // "".toCharArray()); + // remoteRepository = + // ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, uri); + // repositories.add(new RepositoryElem("@localhost//java", + // remoteRepository, credentials)); + } \ No newline at end of file