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 and manipulate distributions (like merge, rename, etc.). Only support
101 * one single repository currently.
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 ColumnLabelProvider() {
123 public String
getText(Object element
) {
124 if (element
instanceof BrowserElem
)
125 return ((BrowserElem
) element
).getLabel();
127 return element
.toString();
131 public Image
getImage(Object element
) {
132 if (element
instanceof BrowserElem
) {
133 BrowserElem bElement
= (BrowserElem
) element
;
134 if (bElement
instanceof RepoElem
) {
135 if (bElement
.isHomeRepo())
136 return DistImages
.IMG_HOME_REPO
;
137 else if (bElement
.isReadOnly
)
138 return DistImages
.IMG_REPO_READONLY
;
140 return DistImages
.IMG_REPO
;
142 } else if (bElement
instanceof DistribGroupElem
) {
143 if (bElement
.isReadOnly
)
144 return DistImages
.IMG_DISTGRP_READONLY
;
146 return DistImages
.IMG_DISTGRP
;
148 } else if (element
instanceof DistributionElem
)
149 return DistImages
.IMG_WKSP
;
154 final Tree tree
= viewer
.getTree();
155 tree
.setHeaderVisible(false);
156 tree
.setLinesVisible(false);
158 viewer
.setContentProvider(new DistributionsContentProvider());
159 viewer
.addDoubleClickListener(new DistributionsDCL());
160 viewer
.setComparator(new BrowserElementComparator());
162 // Enable selection retrieving from outside the view
163 getSite().setSelectionProvider(viewer
);
166 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
167 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
168 viewer
.addDragSupport(operations
, tt
, new ViewDragListener());
169 viewer
.addDropSupport(operations
, tt
, new ViewDropListener(viewer
));
171 MenuManager menuManager
= new MenuManager();
172 Menu menu
= menuManager
.createContextMenu(viewer
.getTree());
173 menuManager
.addMenuListener(new IMenuListener() {
174 public void menuAboutToShow(IMenuManager manager
) {
175 contextMenuAboutToShow(manager
);
178 viewer
.getTree().setMenu(menu
);
179 getSite().registerContextMenu(menuManager
, viewer
);
181 Session nodeSession
= null;
183 nodeSession
= nodeRepository
.login();
185 // make sure base directory is available
186 Node repos
= JcrUtils
.mkdirs(nodeSession
,
187 UserJcrUtils
.getUserHome(nodeSession
).getPath()
188 + RepoConstants
.REPOSITORIES_BASE_PATH
);
191 // register default local java repository
192 String alias
= RepoConstants
.DEFAULT_JAVA_REPOSITORY_ALIAS
;
193 Repository javaRepository
= ArgeoJcrUtils
.getRepositoryByAlias(
194 repositoryFactory
, alias
);
195 if (javaRepository
!= null) {
196 if (!repos
.hasNode(alias
)) {
197 Node repoNode
= repos
.addNode(alias
,
198 ArgeoTypes
.ARGEO_REMOTE_REPOSITORY
);
199 repoNode
.setProperty(ARGEO_URI
, "vm:///" + alias
);
200 repoNode
.addMixin(NodeType
.MIX_TITLE
);
201 repoNode
.setProperty(Property
.JCR_TITLE
, "Internal "
202 + alias
+ " repository");
206 } catch (RepositoryException e
) {
207 throw new SlcException("Cannot register repository", e
);
209 JcrUtils
.logoutQuietly(nodeSession
);
212 viewer
.setInput(nodeRepository
);
215 /** Programatically configure the context menu */
216 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
217 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
218 .getActiveWorkbenchWindow();
219 // Most of the implemented commands support only one selected
221 boolean singleElement
= ((IStructuredSelection
) viewer
.getSelection())
223 // Get Current selected item :
224 Object firstElement
= ((IStructuredSelection
) viewer
.getSelection())
227 if (firstElement
instanceof TreeParent
228 || firstElement
instanceof BrowserElem
) {
229 String targetRepoPath
= null;
231 // Build conditions depending on element type
232 boolean isDistribElem
= false, isRepoElem
= false, isDistribGroupElem
= false;
233 boolean isHomeRepo
= false, isReadOnly
= true;
235 if (firstElement
instanceof DistributionElem
) {
236 DistributionElem de
= (DistributionElem
) firstElement
;
237 isDistribElem
= true;
238 isReadOnly
= de
.isReadOnly();
239 } else if (firstElement
instanceof RepoElem
) {
240 RepoElem re
= (RepoElem
) firstElement
;
242 targetRepoPath
= re
.getRepoPath();
243 isHomeRepo
= re
.isHomeRepo();
244 isReadOnly
= re
.isReadOnly();
245 } else if (firstElement
instanceof DistribGroupElem
) {
246 DistribGroupElem dge
= (DistribGroupElem
) firstElement
;
247 isReadOnly
= dge
.isReadOnly();
248 isDistribGroupElem
= true;
252 CommandHelpers
.refreshCommand(menuManager
, window
,
253 DisplayRepoInformation
.ID
,
254 DisplayRepoInformation
.DEFAULT_LABEL
,
255 DisplayRepoInformation
.DEFAULT_ICON_PATH
, isRepoElem
259 CommandHelpers
.refreshCommand(menuManager
, window
,
260 CreateWorkspace
.ID
, CreateWorkspace
.DEFAULT_LABEL
,
261 CreateWorkspace
.DEFAULT_ICON_PATH
,
262 (isRepoElem
|| isDistribGroupElem
) && singleElement
265 CommandHelpers
.refreshCommand(menuManager
, window
,
266 PublishWorkspace
.ID
, PublishWorkspace
.DEFAULT_LABEL
,
267 PublishWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
268 && singleElement
&& !isReadOnly
);
270 // Register a remote repository
271 CommandHelpers
.refreshCommand(menuManager
, window
,
272 RegisterRepository
.ID
, RegisterRepository
.DEFAULT_LABEL
,
273 RegisterRepository
.DEFAULT_ICON_PATH
, isRepoElem
276 // Unregister a remote repository
277 Map
<String
, String
> params
= new HashMap
<String
, String
>();
278 params
.put(UnregisterRemoteRepo
.PARAM_REPO_PATH
, targetRepoPath
);
279 CommandHelpers
.refreshParameterizedCommand(menuManager
, window
,
280 UnregisterRemoteRepo
.ID
,
281 UnregisterRemoteRepo
.DEFAULT_LABEL
,
282 UnregisterRemoteRepo
.DEFAULT_ICON_PATH
, isRepoElem
283 && !isHomeRepo
&& singleElement
, params
);
286 params
= new HashMap
<String
, String
>();
287 params
.put(Fetch
.PARAM_TARGET_REPO
, targetRepoPath
);
288 CommandHelpers
.refreshParameterizedCommand(menuManager
, window
,
289 Fetch
.ID
, Fetch
.DEFAULT_LABEL
, Fetch
.DEFAULT_ICON_PATH
,
290 isRepoElem
&& singleElement
&& !isReadOnly
, params
);
292 // Normalize workspace
293 CommandHelpers
.refreshCommand(menuManager
, window
,
294 NormalizeDistribution
.ID
,
295 NormalizeDistribution
.DEFAULT_LABEL
,
296 NormalizeDistribution
.DEFAULT_ICON_PATH
, isDistribElem
297 && singleElement
&& !isReadOnly
);
300 CommandHelpers
.refreshCommand(menuManager
, window
,
301 CopyWorkspace
.ID
, CopyWorkspace
.DEFAULT_LABEL
,
302 CopyWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
306 CommandHelpers
.refreshCommand(menuManager
, window
,
307 DeleteWorkspace
.ID
, DeleteWorkspace
.DEFAULT_LABEL
,
308 DeleteWorkspace
.DEFAULT_ICON_PATH
, isDistribElem
309 && singleElement
&& !isReadOnly
);
311 // // Manage workspace authorizations
312 // params = new HashMap<String, String>();
313 // params.put(ManageWorkspaceAuth.PARAM_WORKSPACE_NAME, wsName);
314 // CommandHelpers.refreshParameterizedCommand(menuManager, window,
315 // ManageWorkspaceAuth.ID, ManageWorkspaceAuth.DEFAULT_LABEL,
316 // ManageWorkspaceAuth.DEFAULT_ICON_PATH, isDistribElem
317 // && singleElement && !isReadOnly, params);
319 // } catch (RepositoryException e) {
320 // throw new SlcException("unexpected errror while "
321 // + "building context menu", e);
326 * Exposes some Repository and workspace information about the selected
327 * element without exposing the UI model
329 public class DistributionViewSelectedElement
{
330 public boolean isRepository
= false;
331 public boolean isWorkspaceGroup
= false;
332 public boolean isWorkspace
= false;
333 public boolean isReadOnly
= false;
334 public String repositoryDescription
;
335 public Node repoNode
;
336 public String wkspName
;
337 public String wkspPrefix
;
338 public Repository repository
;
339 public Credentials credentials
;
343 * Returns a {@see DistributionViewSelectedElement} if one and only one
344 * valid element is currently selected.
347 public DistributionViewSelectedElement
getSelectedElement() {
349 IStructuredSelection iss
= (IStructuredSelection
) viewer
.getSelection();
350 if (iss
.isEmpty() || iss
.size() > 1)
353 DistributionViewSelectedElement dvse
= new DistributionViewSelectedElement();
354 Object obj
= iss
.getFirstElement();
355 if (obj
instanceof RepoElem
) {
356 RepoElem re
= (RepoElem
) obj
;
357 dvse
.isRepository
= true;
358 dvse
.isReadOnly
= re
.isReadOnly();
359 dvse
.repository
= re
.getRepository();
360 dvse
.repoNode
= re
.getRepoNode();
361 dvse
.credentials
= re
.getCredentials();
362 dvse
.repositoryDescription
= getRepositoryDescription(re
);
363 } else if (obj
instanceof DistribGroupElem
) {
364 DistribGroupElem dge
= (DistribGroupElem
) obj
;
365 dvse
.isWorkspaceGroup
= true;
366 dvse
.isReadOnly
= dge
.isReadOnly();
367 dvse
.repository
= dge
.getRepoElem().getRepository();
368 dvse
.repoNode
= dge
.getRepoElem().getRepoNode();
369 dvse
.credentials
= dge
.getRepoElem().getCredentials();
370 dvse
.wkspPrefix
= dge
.getLabel();
371 dvse
.repositoryDescription
= getRepositoryDescription(dge
373 } else if (obj
instanceof DistributionElem
) {
374 DistributionElem de
= (DistributionElem
) obj
;
375 dvse
.isWorkspace
= true;
376 dvse
.isReadOnly
= de
.isReadOnly();
377 dvse
.repository
= de
.getRepoElem().getRepository();
378 dvse
.repoNode
= de
.getRepoElem().getRepoNode();
379 dvse
.credentials
= de
.getRepoElem().getCredentials();
380 dvse
.wkspName
= de
.getWorkspaceName();
381 dvse
.repositoryDescription
= getRepositoryDescription(de
387 private String
getRepositoryDescription(RepoElem repo
) {
388 StringBuffer repoDesc
= new StringBuffer();
389 repoDesc
.append(repo
.getLabel());
390 repoDesc
.append(" (");
391 repoDesc
.append(JcrUtils
.get(repo
.getRepoNode(), ARGEO_URI
));
392 repoDesc
.append(")");
393 return repoDesc
.toString();
397 public void setFocus() {
398 viewer
.getTree().setFocus();
402 * Force refresh of the whole view
404 public void refresh() {
405 viewer
.setContentProvider(new DistributionsContentProvider());
411 /** Content provider */
412 private class DistributionsContentProvider
implements ITreeContentProvider
{
414 List
<RepoElem
> repositories
= new ArrayList
<RepoElem
>();
416 public Object
[] getElements(Object input
) {
417 Repository nodeRepository
= (Repository
) input
;
419 if (nodeSession
!= null)
421 nodeSession
= nodeRepository
.login();
423 String reposPath
= UserJcrUtils
.getUserHome(nodeSession
)
424 .getPath() + RepoConstants
.REPOSITORIES_BASE_PATH
;
425 NodeIterator repos
= nodeSession
.getNode(reposPath
).getNodes();
426 while (repos
.hasNext()) {
427 Node repoNode
= repos
.nextNode();
428 if (repoNode
.isNodeType(ArgeoTypes
.ARGEO_REMOTE_REPOSITORY
)) {
429 if (RepoConstants
.DEFAULT_JAVA_REPOSITORY_ALIAS
430 .equals(repoNode
.getName()))
432 .add(new RepoElem(repoNode
, true, false));
433 else if (repoNode
.hasNode(ARGEO_PASSWORD
))
434 repositories
.add(new RepoElem(repoNode
));
437 .add(new RepoElem(repoNode
, false, true));
440 } catch (RepositoryException e
) {
441 throw new SlcException("Cannot get base elements", e
);
443 return repositories
.toArray();
446 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
450 public Object
[] getChildren(Object parentElement
) {
451 if (parentElement
instanceof BrowserElem
) {
452 return ((BrowserElem
) parentElement
).getChildren();
453 } else if (parentElement
instanceof DistributionElem
) {
454 return ((DistributionElem
) parentElement
).getChildren();
459 public Object
getParent(Object element
) {
460 // TODO register repo elem in distribution elem?
464 public boolean hasChildren(Object element
) {
465 if (element
instanceof BrowserElem
) {
467 } else if (element
instanceof DistributionElem
) {
473 public void dispose() {
474 for (RepoElem repoElem
: repositories
)
476 repositories
= new ArrayList
<RepoElem
>();
477 JcrUtils
.logoutQuietly(nodeSession
);
481 /** Add some view specific behaviours to the comparator */
482 private class BrowserElementComparator
extends ArtifactNamesComparator
{
484 public int category(Object element
) {
485 // Home repository always first
486 if (element
instanceof RepoElem
487 && ((RepoElem
) element
).isHomeRepo())
490 return super.category(element
);
494 public int compare(Viewer viewer
, Object e1
, Object e2
) {
495 // reverse order for versions
496 if (e1
instanceof DistributionElem
)
497 return -super.compare(viewer
, e1
, e2
);
499 return super.compare(viewer
, e1
, e2
);
503 /** Abstract class to simplify UI conditions build */
504 abstract class BrowserElem
{
505 private boolean isHomeRepo
= false;
506 private boolean isReadOnly
= false;
508 public BrowserElem(boolean isHomeRepo
, boolean isReadOnly
) {
509 this.isHomeRepo
= isHomeRepo
;
510 this.isReadOnly
= isReadOnly
;
513 public BrowserElem() {
516 public abstract String
getLabel();
518 public abstract Object
[] getChildren();
520 public void dispose() {
523 public boolean isHomeRepo() {
527 public boolean isReadOnly() {
532 /** A software repository */
533 private class RepoElem
extends BrowserElem
{
534 private Node repoNode
;
535 private Repository repository
;
536 private Credentials credentials
;
538 public RepoElem(Node repoNode
, boolean isHomeRepo
, boolean isReadOnly
) {
539 super(isHomeRepo
, isReadOnly
);
540 this.repoNode
= repoNode
;
543 public RepoElem(Node repoNode
) {
544 this.repoNode
= repoNode
;
547 /** Lazily connects to repository */
548 protected void connect() {
549 if (repository
!= null)
551 repository
= RepoUtils
.getRepository(repositoryFactory
, keyring
,
553 credentials
= RepoUtils
.getRepositoryCredentials(keyring
, repoNode
);
556 public String
getLabel() {
558 if (repoNode
.isNodeType(NodeType
.MIX_TITLE
)) {
559 return repoNode
.getProperty(Property
.JCR_TITLE
).getString();
561 return repoNode
.getName();
563 } catch (RepositoryException e
) {
564 throw new SlcException("Cannot read label of " + repoNode
, e
);
568 public String
toString() {
569 return repoNode
.toString();
572 public Object
[] getChildren() {
574 Session session
= null;
576 session
= repository
.login(credentials
);
577 String
[] workspaceNames
= session
.getWorkspace()
578 .getAccessibleWorkspaceNames();
579 // List<DistributionElem> distributionElems = new
580 // ArrayList<DistributionElem>();
581 Map
<String
, DistribGroupElem
> children
= new HashMap
<String
, DistributionsView
.DistribGroupElem
>();
582 for (String workspaceName
: workspaceNames
) {
583 // filter technical workspaces
584 // FIXME: rely on a more robust rule than just wksp name
585 if (workspaceName
.lastIndexOf('-') > 0) {
586 String prefix
= workspaceName
.substring(0,
587 workspaceName
.lastIndexOf('-'));
588 if (!repoNode
.hasNode(workspaceName
))
589 repoNode
.addNode(workspaceName
);
590 repoNode
.getSession().save();
591 if (!children
.containsKey(prefix
)) {
592 children
.put(prefix
, new DistribGroupElem(
593 RepoElem
.this, prefix
));
595 // FIXME remove deleted workspaces
598 return children
.values().toArray();
599 } catch (RepositoryException e
) {
600 throw new SlcException(
601 "Cannot list workspaces for " + repoNode
, e
);
603 JcrUtils
.logoutQuietly(session
);
607 public String
getRepoPath() {
609 return repoNode
.getPath();
610 } catch (RepositoryException e
) {
611 throw new SlcException("Cannot get path for " + repoNode
, e
);
615 public Repository
getRepository() {
620 public Credentials
getCredentials() {
624 public Node
getRepoNode() {
631 * Abstracts a group of distribution, that is a bunch of workspaces with
634 private class DistribGroupElem
extends BrowserElem
{
635 private RepoElem repoElem
;
638 public DistribGroupElem(RepoElem repoElem
, String prefix
) {
639 super(repoElem
.isHomeRepo(), repoElem
.isReadOnly());
640 this.repoElem
= repoElem
;
644 public Object
[] getChildren() {
646 Session session
= null;
648 Repository repository
= repoElem
.getRepository();
649 Node repoNode
= repoElem
.getRepoNode();
650 session
= repository
.login(repoElem
.getCredentials());
652 String
[] workspaceNames
= session
.getWorkspace()
653 .getAccessibleWorkspaceNames();
654 List
<DistributionElem
> distributionElems
= new ArrayList
<DistributionElem
>();
655 for (String workspaceName
: workspaceNames
) {
656 // filter technical workspaces
657 if (workspaceName
.startsWith(name
)) {
658 Node workspaceNode
= repoNode
.hasNode(workspaceName
) ? repoNode
659 .getNode(workspaceName
) : repoNode
660 .addNode(workspaceName
);
661 distributionElems
.add(new DistributionElem(repoElem
,
663 // FIXME remove deleted workspaces
666 return distributionElems
.toArray();
667 } catch (RepositoryException e
) {
668 throw new SlcException("Cannot list workspaces for prefix "
671 JcrUtils
.logoutQuietly(session
);
675 public String
getLabel() {
679 public void dispose() {
682 public RepoElem
getRepoElem() {
688 /** Abstracts a distribution, that is a workspace */
689 private static class DistributionElem
extends TreeParent
{
690 private final RepoElem repoElem
;
691 private final Node workspaceNode
;
694 * Helper to display only version when the workspace name is well
697 private static String
formatName(Node workspaceNode
) {
698 String name
= JcrUtils
.getNameQuietly(workspaceNode
);
699 if (name
!= null && name
.lastIndexOf('-') > 0)
700 return name
.substring(name
.lastIndexOf('-') + 1);
705 public DistributionElem(RepoElem repoElem
, Node workspaceNode
) {
706 super(formatName(workspaceNode
));
707 this.repoElem
= repoElem
;
708 this.workspaceNode
= workspaceNode
;
711 public Node
getWorkspaceNode() {
712 return workspaceNode
;
715 public String
getWorkspaceName() {
716 return JcrUtils
.getNameQuietly(workspaceNode
);
719 public String
getWorkspacePath() {
721 return workspaceNode
.getPath();
722 } catch (RepositoryException e
) {
723 throw new SlcException("Cannot get or add workspace path "
724 + getWorkspaceName(), e
);
728 public String
getRepoPath() {
730 return workspaceNode
.getParent().getPath();
731 } catch (RepositoryException e
) {
732 throw new SlcException("Cannot get or add workspace path "
733 + getWorkspaceName(), e
);
737 public RepoElem
getRepoElem() {
741 public Credentials
getCredentials() {
742 return repoElem
.getCredentials();
745 public boolean isReadOnly() {
746 return repoElem
.isReadOnly();
750 /** Listens to drag */
751 class ViewDragListener
extends DragSourceAdapter
{
752 public void dragSetData(DragSourceEvent event
) {
753 IStructuredSelection selection
= (IStructuredSelection
) viewer
755 if (selection
.getFirstElement() instanceof DistributionElem
) {
756 DistributionElem de
= (DistributionElem
) selection
758 if (TextTransfer
.getInstance().isSupportedType(event
.dataType
)) {
759 event
.data
= de
.getWorkspacePath();
765 /** Listens to drop */
766 class ViewDropListener
extends ViewerDropAdapter
{
768 public ViewDropListener(Viewer viewer
) {
773 public boolean performDrop(Object data
) {
774 DistributionElem sourceDist
= (DistributionElem
) getSelectedObject();
775 RepoElem targetRepo
= (RepoElem
) getCurrentTarget();
777 Boolean ok
= MessageDialog
.openConfirm(getSite().getShell(),
778 "Confirm distribution merge", "Do you want to merge "
779 + sourceDist
.getWorkspaceName() + " (from repo "
780 + sourceDist
.getRepoElem().getLabel()
781 + ") to repo " + targetRepo
.getLabel() + "?");
786 String sourceWorkspace
= sourceDist
.getWorkspaceName();
787 Repository sourceRepository
= RepoUtils
.getRepository(
788 repositoryFactory
, keyring
, sourceDist
789 .getWorkspaceNode().getParent());
790 Credentials sourceCredentials
= RepoUtils
791 .getRepositoryCredentials(keyring
, sourceDist
792 .getWorkspaceNode().getParent());
794 String targetWorkspace
= sourceWorkspace
;
795 Repository targetRepository
= RepoUtils
.getRepository(
796 repositoryFactory
, keyring
, targetRepo
.getRepoNode());
797 Credentials targetCredentials
= RepoUtils
798 .getRepositoryCredentials(keyring
,
799 targetRepo
.getRepoNode());
801 // Open sessions here since the background thread
802 // won't necessarily be authenticated.
803 // Job should close the sessions.
804 Session sourceSession
= sourceRepository
.login(
805 sourceCredentials
, sourceWorkspace
);
806 Session targetSession
;
808 targetSession
= targetRepository
.login(targetCredentials
,
810 } catch (NoSuchWorkspaceException e
) {
811 Session defaultSession
= targetRepository
812 .login(targetCredentials
);
814 defaultSession
.getWorkspace().createWorkspace(
816 } catch (Exception e1
) {
817 throw new SlcException("Cannot create new workspace "
818 + targetWorkspace
, e
);
820 JcrUtils
.logoutQuietly(defaultSession
);
822 targetSession
= targetRepository
.login(targetCredentials
,
826 Job workspaceMergeJob
= new WorkspaceMergeJob(sourceSession
,
828 workspaceMergeJob
.setUser(true);
829 workspaceMergeJob
.schedule();
831 } catch (RepositoryException e
) {
832 throw new SlcException("Cannot process drop from " + sourceDist
833 + " to " + targetRepo
, e
);
838 public boolean validateDrop(Object target
, int operation
,
839 TransferData transferType
) {
840 if (target
instanceof RepoElem
) {
841 if (getSelectedObject() instanceof DistributionElem
) {
842 // check if not same repository
843 String srcRepoPath
= ((DistributionElem
) getSelectedObject())
845 String targetRepoPath
= ((RepoElem
) target
).getRepoPath();
846 return !targetRepoPath
.equals(srcRepoPath
);
853 private static class WorkspaceMergeJob
extends Job
{
854 private Session sourceSession
;
855 private Session targetSession
;
857 public WorkspaceMergeJob(Session sourceSession
, Session targetSession
) {
858 super("Workspace merge");
859 this.sourceSession
= sourceSession
;
860 this.targetSession
= targetSession
;
864 protected IStatus
run(IProgressMonitor eclipseMonitor
) {
865 long begin
= System
.currentTimeMillis();
867 Query countQuery
= sourceSession
870 .createQuery("select file from [nt:file] as file",
872 QueryResult result
= countQuery
.execute();
873 Long expectedCount
= result
.getNodes().getSize();
874 if (log
.isDebugEnabled())
875 log
.debug("Will copy " + expectedCount
+ " files...");
877 ArgeoMonitor monitor
= new EclipseArgeoMonitor(eclipseMonitor
);
879 .beginTask("Copy files", expectedCount
.intValue());
881 Long count
= JcrUtils
.copyFiles(sourceSession
.getRootNode(),
882 targetSession
.getRootNode(), true, monitor
);
885 long duration
= (System
.currentTimeMillis() - begin
) / 1000;// in
887 if (log
.isDebugEnabled())
888 log
.debug("Copied " + count
+ " files in "
889 + (duration
/ 60) + "min " + (duration
% 60) + "s");
891 return Status
.OK_STATUS
;
892 } catch (RepositoryException e
) {
893 return new Status(IStatus
.ERROR
, DistPlugin
.ID
, "Cannot merge",
896 JcrUtils
.logoutQuietly(sourceSession
);
897 JcrUtils
.logoutQuietly(targetSession
);
902 /** Listen to double-clicks */
903 private class DistributionsDCL
implements IDoubleClickListener
{
905 public void doubleClick(DoubleClickEvent event
) {
906 if (event
.getSelection() == null || event
.getSelection().isEmpty())
908 Object obj
= ((IStructuredSelection
) event
.getSelection())
910 if (obj
instanceof DistributionElem
) {
911 DistributionElem distributionElem
= (DistributionElem
) obj
;
912 DistributionEditorInput dei
= new DistributionEditorInput(
913 distributionElem
.getName(),
914 getRepositoryDescription(distributionElem
.getRepoElem()),
915 distributionElem
.getRepoElem().getRepository(),
916 distributionElem
.getWorkspaceName(), distributionElem
919 DistPlugin
.getDefault().getWorkbench()
920 .getActiveWorkbenchWindow().getActivePage()
921 .openEditor(dei
, DistributionEditor
.ID
);
922 } catch (PartInitException e
) {
923 ErrorFeedback
.show("Cannot open editor for "
924 + distributionElem
.getWorkspaceName(), e
);
931 * DEPENDENCY INJECTION
933 public void setRepositoryFactory(RepositoryFactory repositoryFactory
) {
934 this.repositoryFactory
= repositoryFactory
;
937 public void setKeyring(Keyring keyring
) {
938 this.keyring
= keyring
;
941 public void setNodeRepository(Repository repository
) {
942 this.nodeRepository
= repository
;