]> git.argeo.org Git - gpl/argeo-slc.git/blob - plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/FetchWizard.java
Fix single sourcing issue on file download
[gpl/argeo-slc.git] / plugins / org.argeo.slc.client.ui.dist / src / main / java / org / argeo / slc / client / ui / dist / wizards / FetchWizard.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 package org.argeo.slc.client.ui.dist.wizards;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.jcr.Credentials;
24 import javax.jcr.Node;
25 import javax.jcr.NodeIterator;
26 import javax.jcr.Repository;
27 import javax.jcr.RepositoryException;
28 import javax.jcr.RepositoryFactory;
29 import javax.jcr.Session;
30
31 import org.argeo.ArgeoMonitor;
32 import org.argeo.eclipse.ui.EclipseArgeoMonitor;
33 import org.argeo.jcr.ArgeoNames;
34 import org.argeo.jcr.ArgeoTypes;
35 import org.argeo.jcr.JcrUtils;
36 import org.argeo.jcr.UserJcrUtils;
37 import org.argeo.slc.SlcException;
38 import org.argeo.slc.client.ui.dist.DistPlugin;
39 import org.argeo.slc.client.ui.dist.PrivilegedJob;
40 import org.argeo.slc.client.ui.dist.utils.ViewerUtils;
41 import org.argeo.slc.repo.RepoConstants;
42 import org.argeo.slc.repo.RepoSync;
43 import org.argeo.slc.repo.RepoUtils;
44 import org.argeo.util.security.Keyring;
45 import org.eclipse.core.runtime.IProgressMonitor;
46 import org.eclipse.core.runtime.IStatus;
47 import org.eclipse.core.runtime.Status;
48 import org.eclipse.jface.dialogs.MessageDialog;
49 import org.eclipse.jface.viewers.CheckStateChangedEvent;
50 import org.eclipse.jface.viewers.CheckboxTableViewer;
51 import org.eclipse.jface.viewers.ColumnLabelProvider;
52 import org.eclipse.jface.viewers.ICheckStateListener;
53 import org.eclipse.jface.viewers.IStructuredContentProvider;
54 import org.eclipse.jface.viewers.TableViewer;
55 import org.eclipse.jface.viewers.TableViewerColumn;
56 import org.eclipse.jface.viewers.Viewer;
57 import org.eclipse.jface.viewers.ViewerComparator;
58 import org.eclipse.jface.wizard.IWizardPage;
59 import org.eclipse.jface.wizard.Wizard;
60 import org.eclipse.jface.wizard.WizardPage;
61 import org.eclipse.swt.SWT;
62 import org.eclipse.swt.events.ModifyEvent;
63 import org.eclipse.swt.events.ModifyListener;
64 import org.eclipse.swt.events.SelectionAdapter;
65 import org.eclipse.swt.events.SelectionEvent;
66 import org.eclipse.swt.layout.GridData;
67 import org.eclipse.swt.layout.GridLayout;
68 import org.eclipse.swt.widgets.Button;
69 import org.eclipse.swt.widgets.Combo;
70 import org.eclipse.swt.widgets.Composite;
71 import org.eclipse.swt.widgets.Label;
72 import org.eclipse.swt.widgets.Table;
73 import org.eclipse.swt.widgets.Text;
74
75 /**
76 * Defines parameters for the fetch process and run it using a {@link RepoSync}
77 * object.
78 */
79 public class FetchWizard extends Wizard {
80 // private final static Log log = LogFactory.getLog(FetchWizard.class);
81
82 // Business objects
83 private Keyring keyring;
84 private RepositoryFactory repositoryFactory;
85 private Session currSession;
86 private Node targetRepoNode, sourceRepoNode;
87
88 private List<WkspObject> selectedWorkspaces = new ArrayList<WkspObject>();
89
90 // The pages
91 private ChooseWkspPage chooseWkspPage;
92 private RecapPage recapPage;
93
94 // Cache the advanced pages
95 private Map<WkspObject, AdvancedFetchPage> advancedPages = new HashMap<FetchWizard.WkspObject, FetchWizard.AdvancedFetchPage>();
96
97 // Controls with parameters
98 private Button filesOnlyBtn;
99 private Button advancedBtn;
100 private CheckboxTableViewer wkspViewer;
101
102 public FetchWizard(Keyring keyring, RepositoryFactory repositoryFactory,
103 Repository nodeRepository) {
104 super();
105 this.keyring = keyring;
106 this.repositoryFactory = repositoryFactory;
107 try {
108 currSession = nodeRepository.login();
109 } catch (RepositoryException e) {
110 throw new SlcException(
111 "Unexpected error while initializing fetch wizard", e);
112 }
113 }
114
115 @Override
116 public void dispose() {
117 JcrUtils.logoutQuietly(currSession);
118 super.dispose();
119 }
120
121 @Override
122 public void addPages() {
123 try {
124 chooseWkspPage = new ChooseWkspPage();
125 addPage(chooseWkspPage);
126 recapPage = new RecapPage();
127 addPage(recapPage);
128 setWindowTitle("Define Fetch Procedure");
129 } catch (Exception e) {
130 throw new SlcException("Cannot add page to wizard ", e);
131 }
132 }
133
134 @Override
135 public boolean performFinish() {
136 if (!canFinish())
137 return false;
138 try {
139 // Target Repository
140 String targetRepoUri = targetRepoNode.getProperty(
141 ArgeoNames.ARGEO_URI).getString();
142 Repository targetRepo = RepoUtils.getRepository(repositoryFactory,
143 keyring, targetRepoNode);
144 Credentials targetCredentials = RepoUtils.getRepositoryCredentials(
145 keyring, targetRepoNode);
146
147 // Source Repository
148 String sourceRepoUri = sourceRepoNode.getProperty(
149 ArgeoNames.ARGEO_URI).getString();
150 Repository sourceRepo = RepoUtils.getRepository(repositoryFactory,
151 keyring, sourceRepoNode);
152 Credentials sourceCredentials = RepoUtils.getRepositoryCredentials(
153 keyring, sourceRepoNode);
154
155 String msg = "Your are about to fetch data from repository: \n\t"
156 + sourceRepoUri + "\ninto target repository: \n\t"
157 + targetRepoUri + "\nDo you really want to proceed ?";
158
159 boolean result = MessageDialog.openConfirm(DistPlugin.getDefault()
160 .getWorkbench().getDisplay().getActiveShell(),
161 "Confirm Fetch Launch", msg);
162
163 if (result) {
164 RepoSync repoSync = new RepoSync(sourceRepo, sourceCredentials,
165 targetRepo, targetCredentials);
166 repoSync.setTargetRepoUri(targetRepoUri);
167 repoSync.setSourceRepoUri(sourceRepoUri);
168
169 // Specify workspaces to synchronise
170 Map<String, String> wksps = new HashMap<String, String>();
171 for (Object obj : wkspViewer.getCheckedElements()) {
172 WkspObject stn = (WkspObject) obj;
173 wksps.put(stn.srcName, stn.targetName);
174 }
175 repoSync.setWkspMap(wksps);
176
177 // Set the import files only option
178 repoSync.setFilesOnly(filesOnlyBtn.getSelection());
179 FetchJob job = new FetchJob(repoSync);
180 job.setUser(true);
181 job.schedule();
182 }
183 } catch (Exception e) {
184 throw new SlcException(
185 "Unexpected error while launching the fetch", e);
186 }
187 return true;
188 }
189
190 // ///////////////////////////////
191 // ////// THE PAGES
192
193 private class ChooseWkspPage extends WizardPage {
194
195 private Map<String, Node> sourceReposMap;
196 private Combo chooseSourceRepoCmb;
197
198 public ChooseWkspPage() {
199 super("Main");
200 setTitle("Choose workspaces to fetch");
201 setDescription("Check 'advanced fetch' box to "
202 + "rename workspaces and fine tune the process");
203
204 // Initialise with registered Repositories
205 sourceReposMap = getSourceRepoUris();
206 }
207
208 public void createControl(Composite parent) {
209 Composite composite = new Composite(parent, SWT.NO_FOCUS);
210 composite.setLayout(new GridLayout(2, false));
211
212 // Choose source repository combo
213 new Label(composite, SWT.NONE)
214 .setText("Choose a source repository");
215 chooseSourceRepoCmb = new Combo(composite, SWT.BORDER
216 | SWT.V_SCROLL);
217 chooseSourceRepoCmb.setItems(sourceReposMap.keySet().toArray(
218 new String[sourceReposMap.size()]));
219 GridData gd = new GridData(GridData.FILL_HORIZONTAL);
220 chooseSourceRepoCmb.setLayoutData(gd);
221
222 // Check boxes
223 final Button selectAllBtn = new Button(composite, SWT.CHECK);
224 selectAllBtn.setText("Select/Unselect all");
225
226 advancedBtn = new Button(composite, SWT.CHECK);
227 advancedBtn.setText("Advanced fetch");
228 advancedBtn.setToolTipText("Check this for further "
229 + "parameterization of the fetch process");
230
231 // Workspace table
232 Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL
233 | SWT.BORDER | SWT.CHECK);
234 gd = new GridData(SWT.FILL, SWT.FILL, true, true);
235 gd.horizontalSpan = 2;
236 table.setLayoutData(gd);
237 configureWkspTable(table);
238
239 // Import only files
240 filesOnlyBtn = new Button(composite, SWT.CHECK | SWT.WRAP);
241 filesOnlyBtn
242 .setText("Import only files (faster, a normalized action should be launched once done)");
243 filesOnlyBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
244 false, 2, 1));
245
246 // Listeners
247 selectAllBtn.addSelectionListener(new SelectionAdapter() {
248 public void widgetSelected(SelectionEvent e) {
249 wkspViewer.setAllChecked(selectAllBtn.getSelection());
250 getContainer().updateButtons();
251 }
252 });
253
254 // advancedBtn.addSelectionListener(new SelectionAdapter() {
255 // public void widgetSelected(SelectionEvent e) {
256 // if (advancedBtn.getSelection()){
257 //
258 // }
259 // wkspViewer.setAllChecked();
260 // }
261 // });
262
263 chooseSourceRepoCmb.addModifyListener(new ModifyListener() {
264 public void modifyText(ModifyEvent e) {
265 String chosenUri = chooseSourceRepoCmb
266 .getItem(chooseSourceRepoCmb.getSelectionIndex());
267 sourceRepoNode = sourceReposMap.get(chosenUri);
268 wkspViewer.setInput(sourceRepoNode);
269 }
270 });
271
272 wkspViewer.addCheckStateListener(new ICheckStateListener() {
273 public void checkStateChanged(CheckStateChangedEvent event) {
274 getContainer().updateButtons();
275 }
276 });
277
278 // Initialise to first available repo
279 if (chooseSourceRepoCmb.getItemCount() > 0)
280 chooseSourceRepoCmb.select(0);
281
282 // Compulsory
283 setControl(composite);
284 }
285
286 @Override
287 public boolean isPageComplete() {
288 return wkspViewer.getCheckedElements().length != 0;
289 }
290
291 @Override
292 public IWizardPage getNextPage() {
293 // WARNING: page are added and never removed.
294 if (advancedBtn.getSelection()
295 && wkspViewer.getCheckedElements().length != 0) {
296 IWizardPage toReturn = null;
297 for (Object obj : wkspViewer.getCheckedElements()) {
298 WkspObject curr = (WkspObject) obj;
299 // currSelecteds.add(curr);
300 AdvancedFetchPage page;
301 if (!advancedPages.containsKey(curr)) {
302 page = new AdvancedFetchPage(curr.srcName, curr);
303 addPage(page);
304 advancedPages.put(curr, page);
305 } else
306 page = advancedPages.get(curr);
307 if (toReturn == null)
308 toReturn = page;
309 }
310 return toReturn;
311 } else {
312 return recapPage;
313 }
314 }
315
316 // Configure the workspace table
317 private void configureWkspTable(Table table) {
318 table.setLinesVisible(true);
319 table.setHeaderVisible(true);
320 wkspViewer = new CheckboxTableViewer(table);
321
322 // WORKSPACE COLUMNS
323 TableViewerColumn column = ViewerUtils.createTableViewerColumn(
324 wkspViewer, "Source names", SWT.NONE, 250);
325 column.setLabelProvider(new ColumnLabelProvider() {
326 @Override
327 public String getText(Object element) {
328 return ((WkspObject) element).srcName;
329 }
330 });
331
332 // column = ViewerUtils.createTableViewerColumn(wkspViewer, "Size",
333 // SWT.NONE, 250);
334 // column.setLabelProvider(new ColumnLabelProvider() {
335 // @Override
336 // public String getText(Object element) {
337 // return ((WkspObject) element).getFormattedSize();
338 // }
339 // });
340
341 wkspViewer.setContentProvider(new WkspContentProvider());
342 // A basic comparator
343 wkspViewer.setComparator(new WkspComparator());
344 }
345 }
346
347 private class AdvancedFetchPage extends WizardPage {
348
349 private final WkspObject currentWorkspace;
350
351 private Text targetNameTxt;
352
353 protected AdvancedFetchPage(String pageName, WkspObject currentWorkspace) {
354 super(pageName);
355 this.currentWorkspace = currentWorkspace;
356 }
357
358 @Override
359 public void setVisible(boolean visible) {
360 super.setVisible(visible);
361 if (visible) {
362 String msg = "Define advanced parameters to fetch workspace "
363 + currentWorkspace.srcName;
364 setMessage(msg);
365 targetNameTxt.setText(currentWorkspace.targetName);
366 }
367 // else
368 // currentWorkspace.targetName = targetNameTxt.getText();
369 }
370
371 public void createControl(Composite parent) {
372 Composite body = new Composite(parent, SWT.NO_FOCUS);
373 body.setLayout(new GridLayout(2, false));
374 new Label(body, SWT.NONE).setText("Choose a new name");
375 targetNameTxt = new Text(body, SWT.BORDER);
376 targetNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
377 true, false));
378 setControl(body);
379 }
380
381 protected WkspObject getWorkspaceObject() {
382 currentWorkspace.targetName = targetNameTxt.getText();
383 return currentWorkspace;
384 }
385
386 @Override
387 public IWizardPage getNextPage() {
388 // WARNING: page are added and never removed.
389 // IWizardPage toReturn = null;
390 // IWizardPage[] pages = ((Wizard) getContainer()).getPages();
391 Object[] selected = wkspViewer.getCheckedElements();
392 for (int i = 0; i < selected.length - 1; i++) {
393 WkspObject curr = (WkspObject) selected[i];
394 if (curr.equals(currentWorkspace))
395 return advancedPages.get((WkspObject) selected[i + 1]);
396 }
397 return recapPage;
398 }
399 }
400
401 private class RecapPage extends WizardPage {
402
403 private TableViewer recapViewer;
404
405 public RecapPage() {
406 super("Validate and launch");
407 setTitle("Validate and launch");
408 }
409
410 @Override
411 public boolean isPageComplete() {
412 return isCurrentPage();
413 }
414
415 public IWizardPage getNextPage() {
416 // always last....
417 return null;
418 }
419
420 @Override
421 public void setVisible(boolean visible) {
422 super.setVisible(visible);
423 if (visible) {
424 try {
425 String targetRepoUri = targetRepoNode.getProperty(
426 ArgeoNames.ARGEO_URI).getString();
427 String sourceRepoUri = sourceRepoNode.getProperty(
428 ArgeoNames.ARGEO_URI).getString();
429
430 String msg = "Fetch data from: " + sourceRepoUri
431 + "\ninto target repository: " + targetRepoUri;
432 // + "\nDo you really want to proceed ?";
433 setMessage(msg);
434
435 // update values that will be used for the fetch
436 selectedWorkspaces.clear();
437
438 for (Object obj : wkspViewer.getCheckedElements()) {
439 WkspObject curr = (WkspObject) obj;
440
441 if (advancedBtn.getSelection()) {
442 AdvancedFetchPage page = advancedPages.get(curr);
443 selectedWorkspaces.add(page.getWorkspaceObject());
444 } else
445 selectedWorkspaces.add(curr);
446 }
447 recapViewer.setInput(selectedWorkspaces);
448 recapViewer.refresh();
449
450 } catch (RepositoryException re) {
451 throw new SlcException("Unable to get repositories URIs",
452 re);
453 }
454 }
455 }
456
457 public void createControl(Composite parent) {
458 Table table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL
459 | SWT.BORDER);
460 table.setLinesVisible(true);
461 table.setHeaderVisible(true);
462 recapViewer = new TableViewer(table);
463
464 // WORKSPACE COLUMNS
465 TableViewerColumn column = ViewerUtils.createTableViewerColumn(
466 recapViewer, "Sources", SWT.NONE, 250);
467 column.setLabelProvider(new ColumnLabelProvider() {
468 @Override
469 public String getText(Object element) {
470 return ((WkspObject) element).srcName;
471 }
472 });
473
474 column = ViewerUtils.createTableViewerColumn(recapViewer,
475 "targets", SWT.NONE, 250);
476 column.setLabelProvider(new ColumnLabelProvider() {
477 @Override
478 public String getText(Object element) {
479 return ((WkspObject) element).targetName;
480 }
481 });
482
483 recapViewer.setContentProvider(new IStructuredContentProvider() {
484
485 public void inputChanged(Viewer viewer, Object oldInput,
486 Object newInput) {
487 // TODO Auto-generated method stub
488 }
489
490 public void dispose() {
491 }
492
493 public Object[] getElements(Object inputElement) {
494 return selectedWorkspaces.toArray();
495 }
496 });
497
498 // A basic comparator
499 recapViewer.setComparator(new WkspComparator());
500 setControl(table);
501 }
502 }
503
504 /**
505 * Define the privileged job that will be run asynchronously to accomplish
506 * the sync
507 */
508 private class FetchJob extends PrivilegedJob {
509 private RepoSync repoSync;
510
511 public FetchJob(RepoSync repoSync) {
512 super("Fetch");
513 this.repoSync = repoSync;
514 }
515
516 @Override
517 protected IStatus doRun(IProgressMonitor progressMonitor) {
518 try {
519 ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor);
520 repoSync.setMonitor(monitor);
521 repoSync.run();
522 } catch (Exception e) {
523 return new Status(IStatus.ERROR, DistPlugin.ID,
524 "Cannot fetch repository", e);
525 }
526 return Status.OK_STATUS;
527 }
528 }
529
530 // ///////////////////////
531 // Local classes
532 private class WkspObject {
533 protected final String srcName;
534 protected String targetName;
535
536 protected WkspObject(String srcName) {
537 this.srcName = srcName;
538 this.targetName = srcName;
539 }
540
541 @Override
542 public String toString() {
543 return "[" + srcName + " to " + targetName + "]";
544 }
545 }
546
547 private class WkspComparator extends ViewerComparator {
548
549 }
550
551 private class WkspContentProvider implements IStructuredContentProvider {
552 // caches current repo
553 private Node currSourceNodeRepo;
554 private Repository currSourceRepo;
555 private Credentials currSourceCred;
556
557 private List<WkspObject> workspaces = new ArrayList<WkspObject>();
558
559 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
560 if (newInput != null && newInput instanceof Node) {
561 Session session = null;
562 try {
563 Node newRepoNode = (Node) newInput;
564 if (currSourceNodeRepo == null
565 || !newRepoNode.getPath().equals(
566 currSourceNodeRepo.getPath())) {
567
568 // update cache
569 currSourceNodeRepo = newRepoNode;
570 currSourceRepo = RepoUtils.getRepository(
571 repositoryFactory, keyring, currSourceNodeRepo);
572 currSourceCred = RepoUtils.getRepositoryCredentials(
573 keyring, currSourceNodeRepo);
574
575 // reset workspace list
576 wkspViewer.setAllChecked(false);
577 workspaces.clear();
578 session = currSourceRepo.login(currSourceCred);
579 // remove unvalid elements
580 for (String name : session.getWorkspace()
581 .getAccessibleWorkspaceNames())
582 // TODO implement a cleaner way to filter
583 // workspaces out
584 if (name.lastIndexOf('-') > 0) {
585 WkspObject currWksp = new WkspObject(name);
586 // compute wkspace size
587 // TODO implement this
588 // Session currSession = null;
589 // try {
590 // currSession = currSourceRepo.login(
591 // currSourceCred, name);
592 // currWksp.size = JcrUtils
593 // .getNodeApproxSize(currSession
594 // .getNode("/"));
595 //
596 // } catch (RepositoryException re) {
597 // log.warn(
598 // "unable to compute size of workspace "
599 // + name, re);
600 // } finally {
601 // JcrUtils.logoutQuietly(currSession);
602 // }
603 workspaces.add(currWksp);
604 }
605 }
606
607 } catch (RepositoryException e) {
608 throw new SlcException("Unexpected error while "
609 + "initializing fetch wizard", e);
610 } finally {
611 JcrUtils.logoutQuietly(session);
612 }
613 viewer.refresh();
614 }
615 }
616
617 public void dispose() {
618 }
619
620 public Object[] getElements(Object obj) {
621 return workspaces.toArray();
622 }
623 }
624
625 // ////////////////////////////
626 // // Helpers
627
628 // populate available source repo list
629 private Map<String, Node> getSourceRepoUris() {
630 try {
631 Node repoList = currSession.getNode(UserJcrUtils.getUserHome(
632 currSession).getPath()
633 + RepoConstants.REPOSITORIES_BASE_PATH);
634
635 String targetRepoUri = null;
636 if (targetRepoNode != null) {
637 targetRepoUri = targetRepoNode
638 .getProperty(ArgeoNames.ARGEO_URI).getString();
639 }
640 NodeIterator ni = repoList.getNodes();
641 // List<String> sourceRepoNames = new ArrayList<String>();
642 // // caches a map of the source repo nodes with their URI as a key
643 // // to ease further processing
644 Map<String, Node> sourceReposMap = new HashMap<String, Node>();
645 while (ni.hasNext()) {
646 Node currNode = ni.nextNode();
647 if (currNode.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) {
648 String currUri = currNode.getProperty(ArgeoNames.ARGEO_URI)
649 .getString();
650 if (targetRepoUri == null || !targetRepoUri.equals(currUri)) {
651 sourceReposMap.put(currUri, currNode);
652 // sourceRepoNames.add(currUri);
653 }
654 }
655 }
656 return sourceReposMap;
657 // sourceRepoNames.toArray(new String[sourceRepoNames
658 // .size()]);
659 } catch (RepositoryException e) {
660 throw new SlcException("Error while getting repo aliases", e);
661 }
662 }
663
664 public void setTargetRepoNode(Node targetRepoNode) {
665 this.targetRepoNode = targetRepoNode;
666 }
667
668 public void setSourceRepoNode(Node sourceRepoNode) {
669 this.sourceRepoNode = sourceRepoNode;
670 }
671 }