2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.slc
.client
.ui
.dist
.views
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
23 import javax
.jcr
.Credentials
;
24 import javax
.jcr
.NoSuchWorkspaceException
;
25 import javax
.jcr
.Node
;
26 import javax
.jcr
.NodeIterator
;
27 import javax
.jcr
.Property
;
28 import javax
.jcr
.Repository
;
29 import javax
.jcr
.RepositoryException
;
30 import javax
.jcr
.RepositoryFactory
;
31 import javax
.jcr
.Session
;
32 import javax
.jcr
.nodetype
.NodeType
;
33 import javax
.jcr
.query
.Query
;
34 import javax
.jcr
.query
.QueryResult
;
36 import org
.apache
.commons
.logging
.Log
;
37 import org
.apache
.commons
.logging
.LogFactory
;
38 import org
.argeo
.ArgeoMonitor
;
39 import org
.argeo
.eclipse
.ui
.EclipseArgeoMonitor
;
40 import org
.argeo
.eclipse
.ui
.ErrorFeedback
;
41 import org
.argeo
.eclipse
.ui
.TreeParent
;
42 import org
.argeo
.jcr
.ArgeoJcrUtils
;
43 import org
.argeo
.jcr
.ArgeoNames
;
44 import org
.argeo
.jcr
.ArgeoTypes
;
45 import org
.argeo
.jcr
.JcrUtils
;
46 import org
.argeo
.jcr
.UserJcrUtils
;
47 import org
.argeo
.slc
.SlcException
;
48 import org
.argeo
.slc
.client
.ui
.dist
.DistImages
;
49 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
50 import org
.argeo
.slc
.client
.ui
.dist
.commands
.CopyWorkspace
;
51 import org
.argeo
.slc
.client
.ui
.dist
.commands
.CreateWorkspace
;
52 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteWorkspace
;
53 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DisplayRepoInformation
;
54 import org
.argeo
.slc
.client
.ui
.dist
.commands
.Fetch
;
55 import org
.argeo
.slc
.client
.ui
.dist
.commands
.NormalizeDistribution
;
56 import org
.argeo
.slc
.client
.ui
.dist
.commands
.PublishWorkspace
;
57 import org
.argeo
.slc
.client
.ui
.dist
.commands
.RegisterRepository
;
58 import org
.argeo
.slc
.client
.ui
.dist
.commands
.UnregisterRemoteRepo
;
59 import org
.argeo
.slc
.client
.ui
.dist
.editors
.DistributionEditor
;
60 import org
.argeo
.slc
.client
.ui
.dist
.editors
.DistributionEditorInput
;
61 import org
.argeo
.slc
.client
.ui
.dist
.utils
.ArtifactNamesComparator
;
62 import org
.argeo
.slc
.client
.ui
.dist
.utils
.CommandHelpers
;
63 import org
.argeo
.slc
.jcr
.SlcNames
;
64 import org
.argeo
.slc
.repo
.RepoConstants
;
65 import org
.argeo
.slc
.repo
.RepoUtils
;
66 import org
.argeo
.util
.security
.Keyring
;
67 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
68 import org
.eclipse
.core
.runtime
.IStatus
;
69 import org
.eclipse
.core
.runtime
.Status
;
70 import org
.eclipse
.core
.runtime
.jobs
.Job
;
71 import org
.eclipse
.jface
.action
.IMenuListener
;
72 import org
.eclipse
.jface
.action
.IMenuManager
;
73 import org
.eclipse
.jface
.action
.MenuManager
;
74 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
75 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
76 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
77 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
78 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
79 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
80 import org
.eclipse
.jface
.viewers
.TreeViewer
;
81 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
82 import org
.eclipse
.jface
.viewers
.Viewer
;
83 import org
.eclipse
.jface
.viewers
.ViewerDropAdapter
;
84 import org
.eclipse
.swt
.SWT
;
85 import org
.eclipse
.swt
.dnd
.DND
;
86 import org
.eclipse
.swt
.dnd
.DragSourceAdapter
;
87 import org
.eclipse
.swt
.dnd
.DragSourceEvent
;
88 import org
.eclipse
.swt
.dnd
.TextTransfer
;
89 import org
.eclipse
.swt
.dnd
.Transfer
;
90 import org
.eclipse
.swt
.dnd
.TransferData
;
91 import org
.eclipse
.swt
.graphics
.Image
;
92 import org
.eclipse
.swt
.widgets
.Composite
;
93 import org
.eclipse
.swt
.widgets
.Menu
;
94 import org
.eclipse
.swt
.widgets
.Tree
;
95 import org
.eclipse
.ui
.IWorkbenchWindow
;
96 import org
.eclipse
.ui
.PartInitException
;
97 import org
.eclipse
.ui
.part
.ViewPart
;
100 * Browse, manipulate and manage distributions accross multiple repositories
101 * (like fetch, merge, publish, etc.).
103 public class DistributionsView
extends ViewPart
implements SlcNames
, ArgeoNames
{
104 private final static Log log
= LogFactory
.getLog(DistributionsView
.class);
105 public final static String ID
= DistPlugin
.ID
+ ".distributionsView";
107 private Repository nodeRepository
;
108 private RepositoryFactory repositoryFactory
;
109 private Keyring keyring
;
111 private TreeViewer viewer
;
114 public void createPartControl(Composite parent
) {
115 // Define the TableViewer
116 viewer
= new TreeViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
117 | SWT
.FULL_SELECTION
| SWT
.BORDER
);
119 TreeViewerColumn col
= new TreeViewerColumn(viewer
, SWT
.NONE
);
120 col
.getColumn().setWidth(400);
121 col
.setLabelProvider(new DistributionLabelProvider());
123 final Tree tree
= viewer
.getTree();
124 tree
.setHeaderVisible(false);
125 tree
.setLinesVisible(false);
127 viewer
.setContentProvider(new DistributionsContentProvider());
128 viewer
.addDoubleClickListener(new DistributionsDCL());
129 viewer
.setComparator(new BrowserElementComparator());
131 // Enable selection retrieving from outside the view
132 getSite().setSelectionProvider(viewer
);
135 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
136 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
137 viewer
.addDragSupport(operations
, tt
, new ViewDragListener());
138 viewer
.addDropSupport(operations
, tt
, new ViewDropListener(viewer
));
140 MenuManager menuManager
= new MenuManager();
141 Menu menu
= menuManager
.createContextMenu(viewer
.getTree());
142 menuManager
.addMenuListener(new IMenuListener() {
143 public void menuAboutToShow(IMenuManager manager
) {
144 contextMenuAboutToShow(manager
);
147 viewer
.getTree().setMenu(menu
);
148 getSite().registerContextMenu(menuManager
, viewer
);
150 Session nodeSession
= null;
152 nodeSession
= nodeRepository
.login();
154 // make sure base directory is available
155 Node repos
= JcrUtils
.mkdirs(nodeSession
,
156 UserJcrUtils
.getUserHome(nodeSession
).getPath()
157 + RepoConstants
.REPOSITORIES_BASE_PATH
);
160 // register default local java repository
161 String alias
= RepoConstants
.DEFAULT_JAVA_REPOSITORY_ALIAS
;
162 Repository javaRepository
= ArgeoJcrUtils
.getRepositoryByAlias(
163 repositoryFactory
, alias
);
164 if (javaRepository
!= null) {
165 if (!repos
.hasNode(alias
)) {
166 Node repoNode
= repos
.addNode(alias
,
167 ArgeoTypes
.ARGEO_REMOTE_REPOSITORY
);
168 repoNode
.setProperty(ARGEO_URI
, "vm:///" + alias
);
169 repoNode
.addMixin(NodeType
.MIX_TITLE
);
170 repoNode
.setProperty(Property
.JCR_TITLE
,
171 RepoConstants
.DEFAULT_JAVA_REPOSITORY_LABEL
);
175 } catch (RepositoryException e
) {
176 throw new SlcException("Cannot register repository", e
);
178 JcrUtils
.logoutQuietly(nodeSession
);
181 viewer
.setInput(nodeRepository
);
182 viewer
.expandToLevel(2);
185 /** Programatically configure the context menu */
186 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
187 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
188 .getActiveWorkbenchWindow();
189 // Most of the implemented commands support only one selected
191 boolean singleElement
= ((IStructuredSelection
) viewer
.getSelection())
193 // Get Current selected item :
194 Object firstElement
= ((IStructuredSelection
) viewer
.getSelection())
197 if (firstElement
instanceof TreeParent
198 || firstElement
instanceof BrowserElem
) {
199 String targetRepoPath
= null;
201 // Build conditions depending on element type
202 boolean isDistribElem
= false, isRepoElem
= false, isDistribGroupElem
= false;
203 boolean isHomeRepo
= false, isReadOnly
= true;
205 if (firstElement
instanceof DistributionElem
) {
206 DistributionElem de
= (DistributionElem
) firstElement
;
207 isDistribElem
= true;
208 isReadOnly
= de
.isReadOnly();
209 } else if (firstElement
instanceof RepoElem
) {
210 RepoElem re
= (RepoElem
) firstElement
;
212 targetRepoPath
= re
.getRepoPath();
213 isHomeRepo
= re
.isHomeRepo();
214 isReadOnly
= re
.isReadOnly();
215 } else if (firstElement
instanceof DistribGroupElem
) {
216 DistribGroupElem dge
= (DistribGroupElem
) firstElement
;
217 isReadOnly
= dge
.isReadOnly();
218 isDistribGroupElem
= true;
222 CommandHelpers
.refreshCommand(menuManager
, window
,
223 DisplayRepoInformation
.ID
,
224 DisplayRepoInformation
.DEFAULT_LABEL
,
225 DisplayRepoInformation
.DEFAULT_ICON_PATH
, isRepoElem
229 CommandHelpers
.refreshCommand(menuManager
, window
,
230 CreateWorkspace
.ID
, CreateWorkspace
.DEFAULT_LABEL
,
231 CreateWorkspace
.DEFAULT_ICON_PATH
,
232 (isRepoElem
|| isDistribGroupElem
) && singleElement
235 CommandHelpers
.refreshCommand(menuManager
, window
,
236 PublishWorkspace
.ID
, PublishWorkspace
.DEFAULT_LABEL
,
237 PublishWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
238 && singleElement
&& !isReadOnly
);
240 // Register a remote repository
241 CommandHelpers
.refreshCommand(menuManager
, window
,
242 RegisterRepository
.ID
, RegisterRepository
.DEFAULT_LABEL
,
243 RegisterRepository
.DEFAULT_ICON_PATH
, isRepoElem
246 // Unregister a remote repository
247 Map
<String
, String
> params
= new HashMap
<String
, String
>();
248 params
.put(UnregisterRemoteRepo
.PARAM_REPO_PATH
, targetRepoPath
);
249 CommandHelpers
.refreshParameterizedCommand(menuManager
, window
,
250 UnregisterRemoteRepo
.ID
,
251 UnregisterRemoteRepo
.DEFAULT_LABEL
,
252 UnregisterRemoteRepo
.DEFAULT_ICON_PATH
, isRepoElem
253 && !isHomeRepo
&& singleElement
, params
);
256 params
= new HashMap
<String
, String
>();
257 params
.put(Fetch
.PARAM_TARGET_REPO
, targetRepoPath
);
258 CommandHelpers
.refreshParameterizedCommand(menuManager
, window
,
259 Fetch
.ID
, Fetch
.DEFAULT_LABEL
, Fetch
.DEFAULT_ICON_PATH
,
260 isRepoElem
&& singleElement
&& !isReadOnly
, params
);
262 // Normalize workspace
263 CommandHelpers
.refreshCommand(menuManager
, window
,
264 NormalizeDistribution
.ID
,
265 NormalizeDistribution
.DEFAULT_LABEL
,
266 NormalizeDistribution
.DEFAULT_ICON_PATH
, isDistribElem
267 && singleElement
&& !isReadOnly
);
270 CommandHelpers
.refreshCommand(menuManager
, window
,
271 CopyWorkspace
.ID
, CopyWorkspace
.DEFAULT_LABEL
,
272 CopyWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
276 CommandHelpers
.refreshCommand(menuManager
, window
,
277 DeleteWorkspace
.ID
, DeleteWorkspace
.DEFAULT_LABEL
,
278 DeleteWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
279 && singleElement
&& !isReadOnly
);
281 // // Manage workspace authorizations
282 // params = new HashMap<String, String>();
283 // params.put(ManageWorkspaceAuth.PARAM_WORKSPACE_NAME, wsName);
284 // CommandHelpers.refreshParameterizedCommand(menuManager, window,
285 // ManageWorkspaceAuth.ID, ManageWorkspaceAuth.DEFAULT_LABEL,
286 // ManageWorkspaceAuth.DEFAULT_ICON_PATH, isDistribElem
287 // && singleElement && !isReadOnly, params);
289 // } catch (RepositoryException e) {
290 // throw new SlcException("unexpected errror while "
291 // + "building context menu", e);
296 * Exposes some Repository and workspace information about the selected
297 * element without exposing the UI model
299 public class DistributionViewSelectedElement
{
300 public boolean isRepository
= false;
301 public boolean isWorkspaceGroup
= false;
302 public boolean isWorkspace
= false;
303 public boolean isReadOnly
= false;
304 public String repositoryDescription
;
305 public Node repoNode
;
306 public String wkspName
;
307 public String wkspPrefix
;
308 public Repository repository
;
309 public Credentials credentials
;
313 * Returns a {@see DistributionViewSelectedElement} if one and only one
314 * valid element is currently selected.
317 public DistributionViewSelectedElement
getSelectedElement() {
319 IStructuredSelection iss
= (IStructuredSelection
) viewer
.getSelection();
320 if (iss
.isEmpty() || iss
.size() > 1)
323 DistributionViewSelectedElement dvse
= new DistributionViewSelectedElement();
324 Object obj
= iss
.getFirstElement();
325 if (obj
instanceof RepoElem
) {
326 RepoElem re
= (RepoElem
) obj
;
327 dvse
.isRepository
= true;
328 dvse
.isReadOnly
= re
.isReadOnly();
329 dvse
.repository
= re
.getRepository();
330 dvse
.repoNode
= re
.getRepoNode();
331 dvse
.credentials
= re
.getCredentials();
332 dvse
.repositoryDescription
= getRepositoryDescription(re
);
333 } else if (obj
instanceof DistribGroupElem
) {
334 DistribGroupElem dge
= (DistribGroupElem
) obj
;
335 dvse
.isWorkspaceGroup
= true;
336 dvse
.isReadOnly
= dge
.isReadOnly();
337 dvse
.repository
= dge
.getRepoElem().getRepository();
338 dvse
.repoNode
= dge
.getRepoElem().getRepoNode();
339 dvse
.credentials
= dge
.getRepoElem().getCredentials();
340 dvse
.wkspPrefix
= dge
.getLabel();
341 dvse
.repositoryDescription
= getRepositoryDescription(dge
343 } else if (obj
instanceof DistributionElem
) {
344 DistributionElem de
= (DistributionElem
) obj
;
345 dvse
.isWorkspace
= true;
346 dvse
.isReadOnly
= de
.isReadOnly();
347 dvse
.repository
= de
.getRepoElem().getRepository();
348 dvse
.repoNode
= de
.getRepoElem().getRepoNode();
349 dvse
.credentials
= de
.getRepoElem().getCredentials();
350 dvse
.wkspName
= de
.getWorkspaceName();
351 dvse
.repositoryDescription
= getRepositoryDescription(de
357 private String
getRepositoryDescription(RepoElem repo
) {
358 StringBuffer repoDesc
= new StringBuffer();
359 repoDesc
.append(repo
.getLabel());
360 repoDesc
.append(" (");
361 repoDesc
.append(JcrUtils
.get(repo
.getRepoNode(), ARGEO_URI
));
362 repoDesc
.append(")");
363 return repoDesc
.toString();
367 public void setFocus() {
368 viewer
.getTree().setFocus();
372 * Force refresh of the whole view
374 public void refresh() {
375 viewer
.setContentProvider(new DistributionsContentProvider());
381 private class DistributionLabelProvider
extends ColumnLabelProvider
{
383 public String
getText(Object element
) {
384 if (element
instanceof BrowserElem
)
385 return ((BrowserElem
) element
).getLabel();
387 return element
.toString();
391 public Image
getImage(Object element
) {
392 if (element
instanceof BrowserElem
) {
393 BrowserElem bElement
= (BrowserElem
) element
;
394 if (bElement
instanceof RepoElem
) {
395 if (bElement
.isHomeRepo())
396 return DistImages
.IMG_HOME_REPO
;
397 else if (bElement
.isReadOnly())
398 return DistImages
.IMG_REPO_READONLY
;
400 return DistImages
.IMG_REPO
;
402 } else if (bElement
instanceof DistribGroupElem
) {
403 return DistImages
.IMG_WKSP
;
405 } else if (element
instanceof DistributionElem
)
406 if (((DistributionElem
) element
).isReadOnly())
407 return DistImages
.IMG_DISTGRP_READONLY
;
409 return DistImages
.IMG_DISTGRP
;
415 /** Content provider */
416 private class DistributionsContentProvider
implements ITreeContentProvider
{
418 List
<RepoElem
> repositories
= new ArrayList
<RepoElem
>();
420 public Object
[] getElements(Object input
) {
421 Repository nodeRepository
= (Repository
) input
;
423 if (nodeSession
!= null)
425 nodeSession
= nodeRepository
.login();
427 String reposPath
= UserJcrUtils
.getUserHome(nodeSession
)
428 .getPath() + RepoConstants
.REPOSITORIES_BASE_PATH
;
429 NodeIterator repos
= nodeSession
.getNode(reposPath
).getNodes();
430 while (repos
.hasNext()) {
431 Node repoNode
= repos
.nextNode();
432 if (repoNode
.isNodeType(ArgeoTypes
.ARGEO_REMOTE_REPOSITORY
)) {
433 if (RepoConstants
.DEFAULT_JAVA_REPOSITORY_ALIAS
434 .equals(repoNode
.getName()))
436 .add(new RepoElem(repoNode
, true, false));
437 else if (repoNode
.hasNode(ARGEO_PASSWORD
))
438 repositories
.add(new RepoElem(repoNode
));
441 .add(new RepoElem(repoNode
, false, true));
444 } catch (RepositoryException e
) {
445 throw new SlcException("Cannot get base elements", e
);
447 return repositories
.toArray();
450 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
453 public Object
[] getChildren(Object parentElement
) {
454 if (parentElement
instanceof BrowserElem
) {
455 return ((BrowserElem
) parentElement
).getChildren();
456 } else if (parentElement
instanceof DistributionElem
) {
457 return ((DistributionElem
) parentElement
).getChildren();
462 public Object
getParent(Object element
) {
463 // TODO register repo elem in distribution elem?
467 public boolean hasChildren(Object element
) {
468 if (element
instanceof BrowserElem
) {
470 } else if (element
instanceof DistributionElem
) {
476 public void dispose() {
477 for (RepoElem repoElem
: repositories
)
479 repositories
= new ArrayList
<RepoElem
>();
480 JcrUtils
.logoutQuietly(nodeSession
);
484 /** Add some view specific behaviours to the comparator */
485 private class BrowserElementComparator
extends ArtifactNamesComparator
{
487 public int category(Object element
) {
488 // Home repository always first
489 if (element
instanceof RepoElem
490 && ((RepoElem
) element
).isHomeRepo())
493 return super.category(element
);
497 public int compare(Viewer viewer
, Object e1
, Object e2
) {
498 // reverse order for versions
499 if (e1
instanceof DistributionElem
)
500 return -super.compare(viewer
, e1
, e2
);
502 return super.compare(viewer
, e1
, e2
);
506 /** Abstract class to simplify UI conditions build */
507 abstract class BrowserElem
{
508 private boolean isHomeRepo
= false;
509 private boolean isReadOnly
= false;
511 public BrowserElem(boolean isHomeRepo
, boolean isReadOnly
) {
512 this.isHomeRepo
= isHomeRepo
;
513 this.isReadOnly
= isReadOnly
;
516 public BrowserElem() {
519 public abstract String
getLabel();
521 public abstract Object
[] getChildren();
523 public void dispose() {
526 public boolean isHomeRepo() {
530 public boolean isReadOnly() {
535 /** A software repository */
536 private class RepoElem
extends BrowserElem
{
537 private Node repoNode
;
538 private Repository repository
;
539 private Credentials credentials
;
541 public RepoElem(Node repoNode
, boolean isHomeRepo
, boolean isReadOnly
) {
542 super(isHomeRepo
, isReadOnly
);
543 this.repoNode
= repoNode
;
546 public RepoElem(Node repoNode
) {
547 this.repoNode
= repoNode
;
550 /** Lazily connects to repository */
551 protected void connect() {
552 if (repository
!= null)
554 repository
= RepoUtils
.getRepository(repositoryFactory
, keyring
,
556 credentials
= RepoUtils
.getRepositoryCredentials(keyring
, repoNode
);
559 public String
getLabel() {
561 if (repoNode
.isNodeType(NodeType
.MIX_TITLE
)) {
562 return repoNode
.getProperty(Property
.JCR_TITLE
).getString();
564 return repoNode
.getName();
566 } catch (RepositoryException e
) {
567 throw new SlcException("Cannot read label of " + repoNode
, e
);
571 public String
toString() {
572 return repoNode
.toString();
575 public Object
[] getChildren() {
577 Session session
= null;
579 session
= repository
.login(credentials
);
580 String
[] workspaceNames
= session
.getWorkspace()
581 .getAccessibleWorkspaceNames();
582 // List<DistributionElem> distributionElems = new
583 // ArrayList<DistributionElem>();
584 Map
<String
, DistribGroupElem
> children
= new HashMap
<String
, DistributionsView
.DistribGroupElem
>();
585 for (String workspaceName
: workspaceNames
) {
586 // filter technical workspaces
587 // FIXME: rely on a more robust rule than just wksp name
588 if (workspaceName
.lastIndexOf('-') > 0) {
589 String prefix
= workspaceName
.substring(0,
590 workspaceName
.lastIndexOf('-'));
591 if (!repoNode
.hasNode(workspaceName
))
592 repoNode
.addNode(workspaceName
);
593 repoNode
.getSession().save();
594 if (!children
.containsKey(prefix
)) {
595 children
.put(prefix
, new DistribGroupElem(
596 RepoElem
.this, prefix
));
598 // FIXME remove deleted workspaces
601 return children
.values().toArray();
602 } catch (RepositoryException e
) {
603 throw new SlcException(
604 "Cannot list workspaces for " + repoNode
, e
);
606 JcrUtils
.logoutQuietly(session
);
610 public String
getRepoPath() {
612 return repoNode
.getPath();
613 } catch (RepositoryException e
) {
614 throw new SlcException("Cannot get path for " + repoNode
, e
);
618 public Repository
getRepository() {
623 public Credentials
getCredentials() {
627 public Node
getRepoNode() {
634 * Abstracts a group of distribution, that is a bunch of workspaces with
637 private class DistribGroupElem
extends BrowserElem
{
638 private RepoElem repoElem
;
641 public DistribGroupElem(RepoElem repoElem
, String prefix
) {
642 super(repoElem
.isHomeRepo(), repoElem
.isReadOnly());
643 this.repoElem
= repoElem
;
647 public Object
[] getChildren() {
649 Session session
= null;
651 Repository repository
= repoElem
.getRepository();
652 Node repoNode
= repoElem
.getRepoNode();
653 session
= repository
.login(repoElem
.getCredentials());
655 String
[] workspaceNames
= session
.getWorkspace()
656 .getAccessibleWorkspaceNames();
657 List
<DistributionElem
> distributionElems
= new ArrayList
<DistributionElem
>();
658 for (String workspaceName
: workspaceNames
) {
659 // filter technical workspaces
660 if (workspaceName
.startsWith(name
)) {
661 Node workspaceNode
= repoNode
.hasNode(workspaceName
) ? repoNode
662 .getNode(workspaceName
) : repoNode
663 .addNode(workspaceName
);
664 distributionElems
.add(new DistributionElem(repoElem
,
666 // FIXME remove deleted workspaces
669 return distributionElems
.toArray();
670 } catch (RepositoryException e
) {
671 throw new SlcException("Cannot list workspaces for prefix "
674 JcrUtils
.logoutQuietly(session
);
678 public String
getLabel() {
682 public String
toString() {
686 public void dispose() {
689 public RepoElem
getRepoElem() {
695 /** Abstracts a distribution, that is a workspace */
696 private static class DistributionElem
extends TreeParent
{
697 private final RepoElem repoElem
;
698 private final Node workspaceNode
;
701 * Helper to display only version when the workspace name is well
704 private static String
formatName(Node workspaceNode
) {
705 String name
= JcrUtils
.getNameQuietly(workspaceNode
);
706 if (name
!= null && name
.lastIndexOf('-') > 0)
707 return name
.substring(name
.lastIndexOf('-') + 1);
712 public DistributionElem(RepoElem repoElem
, Node workspaceNode
) {
713 super(formatName(workspaceNode
));
714 this.repoElem
= repoElem
;
715 this.workspaceNode
= workspaceNode
;
718 public Node
getWorkspaceNode() {
719 return workspaceNode
;
722 public String
getWorkspaceName() {
723 return JcrUtils
.getNameQuietly(workspaceNode
);
726 public String
getWorkspacePath() {
728 return workspaceNode
.getPath();
729 } catch (RepositoryException e
) {
730 throw new SlcException("Cannot get or add workspace path "
731 + getWorkspaceName(), e
);
735 public String
getRepoPath() {
737 return workspaceNode
.getParent().getPath();
738 } catch (RepositoryException e
) {
739 throw new SlcException("Cannot get or add workspace path "
740 + getWorkspaceName(), e
);
744 public RepoElem
getRepoElem() {
748 public Credentials
getCredentials() {
749 return repoElem
.getCredentials();
752 public boolean isReadOnly() {
753 return repoElem
.isReadOnly();
757 /** Listens to drag */
758 class ViewDragListener
extends DragSourceAdapter
{
759 public void dragSetData(DragSourceEvent event
) {
760 IStructuredSelection selection
= (IStructuredSelection
) viewer
762 if (selection
.getFirstElement() instanceof DistributionElem
) {
763 DistributionElem de
= (DistributionElem
) selection
765 if (TextTransfer
.getInstance().isSupportedType(event
.dataType
)) {
766 event
.data
= de
.getWorkspacePath();
772 /** Listens to drop */
773 class ViewDropListener
extends ViewerDropAdapter
{
775 public ViewDropListener(Viewer viewer
) {
780 public boolean performDrop(Object data
) {
781 DistributionElem sourceDist
= (DistributionElem
) getSelectedObject();
782 RepoElem targetRepo
= (RepoElem
) getCurrentTarget();
784 Boolean ok
= MessageDialog
.openConfirm(getSite().getShell(),
785 "Confirm distribution merge", "Do you want to merge "
786 + sourceDist
.getWorkspaceName() + " (from repo "
787 + sourceDist
.getRepoElem().getLabel()
788 + ") to repo " + targetRepo
.getLabel() + "?");
793 String sourceWorkspace
= sourceDist
.getWorkspaceName();
794 Repository sourceRepository
= RepoUtils
.getRepository(
795 repositoryFactory
, keyring
, sourceDist
796 .getWorkspaceNode().getParent());
797 Credentials sourceCredentials
= RepoUtils
798 .getRepositoryCredentials(keyring
, sourceDist
799 .getWorkspaceNode().getParent());
801 String targetWorkspace
= sourceWorkspace
;
802 Repository targetRepository
= RepoUtils
.getRepository(
803 repositoryFactory
, keyring
, targetRepo
.getRepoNode());
804 Credentials targetCredentials
= RepoUtils
805 .getRepositoryCredentials(keyring
,
806 targetRepo
.getRepoNode());
808 // Open sessions here since the background thread
809 // won't necessarily be authenticated.
810 // Job should close the sessions.
811 Session sourceSession
= sourceRepository
.login(
812 sourceCredentials
, sourceWorkspace
);
813 Session targetSession
;
815 targetSession
= targetRepository
.login(targetCredentials
,
817 } catch (NoSuchWorkspaceException e
) {
818 Session defaultSession
= targetRepository
819 .login(targetCredentials
);
821 defaultSession
.getWorkspace().createWorkspace(
823 } catch (Exception e1
) {
824 throw new SlcException("Cannot create new workspace "
825 + targetWorkspace
, e
);
827 JcrUtils
.logoutQuietly(defaultSession
);
829 targetSession
= targetRepository
.login(targetCredentials
,
833 Job workspaceMergeJob
= new WorkspaceMergeJob(sourceSession
,
835 workspaceMergeJob
.setUser(true);
836 workspaceMergeJob
.schedule();
838 } catch (RepositoryException e
) {
839 throw new SlcException("Cannot process drop from " + sourceDist
840 + " to " + targetRepo
, e
);
845 public boolean validateDrop(Object target
, int operation
,
846 TransferData transferType
) {
847 if (target
instanceof RepoElem
) {
848 if (getSelectedObject() instanceof DistributionElem
) {
849 // check if not same repository
850 String srcRepoPath
= ((DistributionElem
) getSelectedObject())
852 String targetRepoPath
= ((RepoElem
) target
).getRepoPath();
853 return !targetRepoPath
.equals(srcRepoPath
);
860 private static class WorkspaceMergeJob
extends Job
{
861 private Session sourceSession
;
862 private Session targetSession
;
864 public WorkspaceMergeJob(Session sourceSession
, Session targetSession
) {
865 super("Workspace merge");
866 this.sourceSession
= sourceSession
;
867 this.targetSession
= targetSession
;
871 protected IStatus
run(IProgressMonitor eclipseMonitor
) {
872 long begin
= System
.currentTimeMillis();
874 Query countQuery
= sourceSession
877 .createQuery("select file from [nt:file] as file",
879 QueryResult result
= countQuery
.execute();
880 Long expectedCount
= result
.getNodes().getSize();
881 if (log
.isDebugEnabled())
882 log
.debug("Will copy " + expectedCount
+ " files...");
884 ArgeoMonitor monitor
= new EclipseArgeoMonitor(eclipseMonitor
);
886 .beginTask("Copy files", expectedCount
.intValue());
888 Long count
= JcrUtils
.copyFiles(sourceSession
.getRootNode(),
889 targetSession
.getRootNode(), true, monitor
);
892 long duration
= (System
.currentTimeMillis() - begin
) / 1000;// in
894 if (log
.isDebugEnabled())
895 log
.debug("Copied " + count
+ " files in "
896 + (duration
/ 60) + "min " + (duration
% 60) + "s");
898 return Status
.OK_STATUS
;
899 } catch (RepositoryException e
) {
900 return new Status(IStatus
.ERROR
, DistPlugin
.ID
, "Cannot merge",
903 JcrUtils
.logoutQuietly(sourceSession
);
904 JcrUtils
.logoutQuietly(targetSession
);
909 /** Listen to double-clicks */
910 private class DistributionsDCL
implements IDoubleClickListener
{
912 public void doubleClick(DoubleClickEvent event
) {
913 if (event
.getSelection() == null || event
.getSelection().isEmpty())
915 Object obj
= ((IStructuredSelection
) event
.getSelection())
917 if (obj
instanceof DistributionElem
) {
918 DistributionElem distributionElem
= (DistributionElem
) obj
;
919 DistributionEditorInput dei
= new DistributionEditorInput(
920 distributionElem
.getName(),
921 getRepositoryDescription(distributionElem
.getRepoElem()),
922 distributionElem
.getRepoElem().getRepository(),
923 distributionElem
.getWorkspaceName(), distributionElem
926 DistPlugin
.getDefault().getWorkbench()
927 .getActiveWorkbenchWindow().getActivePage()
928 .openEditor(dei
, DistributionEditor
.ID
);
929 } catch (PartInitException e
) {
930 ErrorFeedback
.show("Cannot open editor for "
931 + distributionElem
.getWorkspaceName(), e
);
938 * DEPENDENCY INJECTION
940 public void setRepositoryFactory(RepositoryFactory repositoryFactory
) {
941 this.repositoryFactory
= repositoryFactory
;
944 public void setKeyring(Keyring keyring
) {
945 this.keyring
= keyring
;
948 public void setNodeRepository(Repository repository
) {
949 this.nodeRepository
= repository
;