View Javadoc
1   package org.argeo.cms.e4.users;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.Map;
7   
8   import javax.transaction.SystemException;
9   import javax.transaction.UserTransaction;
10  
11  import org.apache.commons.logging.Log;
12  import org.apache.commons.logging.LogFactory;
13  import org.argeo.api.NodeConstants;
14  import org.argeo.cms.CmsException;
15  import org.argeo.cms.auth.CurrentUser;
16  import org.argeo.cms.auth.UserAdminUtils;
17  import org.argeo.cms.e4.users.providers.CommonNameLP;
18  import org.argeo.cms.e4.users.providers.DomainNameLP;
19  import org.argeo.cms.e4.users.providers.MailLP;
20  import org.argeo.cms.e4.users.providers.UserNameLP;
21  import org.argeo.eclipse.ui.ColumnDefinition;
22  import org.argeo.eclipse.ui.EclipseUiUtils;
23  import org.argeo.eclipse.ui.parts.LdifUsersTable;
24  import org.argeo.naming.LdapAttrs;
25  import org.argeo.naming.LdapObjs;
26  import org.eclipse.jface.dialogs.IPageChangeProvider;
27  import org.eclipse.jface.dialogs.IPageChangedListener;
28  import org.eclipse.jface.dialogs.MessageDialog;
29  import org.eclipse.jface.dialogs.PageChangedEvent;
30  import org.eclipse.jface.wizard.IWizardContainer;
31  import org.eclipse.jface.wizard.Wizard;
32  import org.eclipse.jface.wizard.WizardPage;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.events.ModifyEvent;
35  import org.eclipse.swt.events.ModifyListener;
36  import org.eclipse.swt.events.SelectionAdapter;
37  import org.eclipse.swt.events.SelectionEvent;
38  import org.eclipse.swt.layout.GridData;
39  import org.eclipse.swt.layout.GridLayout;
40  import org.eclipse.swt.widgets.Button;
41  import org.eclipse.swt.widgets.Combo;
42  import org.eclipse.swt.widgets.Composite;
43  import org.eclipse.swt.widgets.Text;
44  import org.osgi.framework.InvalidSyntaxException;
45  import org.osgi.service.useradmin.Role;
46  import org.osgi.service.useradmin.User;
47  import org.osgi.service.useradmin.UserAdminEvent;
48  
49  /** Wizard to update users */
50  public class UserBatchUpdateWizard extends Wizard {
51  
52  	private final static Log log = LogFactory.getLog(UserBatchUpdateWizard.class);
53  	private UserAdminWrapper userAdminWrapper;
54  
55  	// pages
56  	private ChooseCommandWizardPage chooseCommandPage;
57  	private ChooseUsersWizardPage userListPage;
58  	private ValidateAndLaunchWizardPage validatePage;
59  
60  	// Various implemented commands keys
61  	private final static String CMD_UPDATE_PASSWORD = "resetPassword";
62  	private final static String CMD_UPDATE_EMAIL = "resetEmail";
63  	private final static String CMD_GROUP_MEMBERSHIP = "groupMembership";
64  
65  	private final Map<String, String> commands = new HashMap<String, String>() {
66  		private static final long serialVersionUID = 1L;
67  		{
68  			put("Reset password(s)", CMD_UPDATE_PASSWORD);
69  			put("Reset email(s)", CMD_UPDATE_EMAIL);
70  			// TODO implement role / group management
71  			// put("Add/Remove from group", CMD_GROUP_MEMBERSHIP);
72  		}
73  	};
74  
75  	public UserBatchUpdateWizard(UserAdminWrapper userAdminWrapper) {
76  		this.userAdminWrapper = userAdminWrapper;
77  	}
78  
79  	@Override
80  	public void addPages() {
81  		chooseCommandPage = new ChooseCommandWizardPage();
82  		addPage(chooseCommandPage);
83  		userListPage = new ChooseUsersWizardPage();
84  		addPage(userListPage);
85  		validatePage = new ValidateAndLaunchWizardPage();
86  		addPage(validatePage);
87  	}
88  
89  	@Override
90  	public boolean performFinish() {
91  		if (!canFinish())
92  			return false;
93  		UserTransaction ut = userAdminWrapper.getUserTransaction();
94  		try {
95  			if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION
96  					&& !MessageDialog.openConfirm(getShell(), "Existing Transaction",
97  							"A user transaction is already existing, " + "are you sure you want to proceed ?"))
98  				return false;
99  		} catch (SystemException e) {
100 			throw new CmsException("Cannot get user transaction state " + "before user batch update", e);
101 		}
102 
103 		// We cannot use jobs, user modifications are still meant to be done in
104 		// the UIThread
105 		// UpdateJob job = null;
106 		// if (job != null)
107 		// job.schedule();
108 
109 		if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) {
110 			char[] newValue = chooseCommandPage.getPwdValue();
111 			if (newValue == null)
112 				throw new CmsException("Password cannot be null or an empty string");
113 			ResetPassword job = new ResetPassword(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
114 			job.doUpdate();
115 		} else if (CMD_UPDATE_EMAIL.equals(chooseCommandPage.getCommand())) {
116 			String newValue = chooseCommandPage.getEmailValue();
117 			if (newValue == null)
118 				throw new CmsException("Password cannot be null or an empty string");
119 			ResetEmail job = new ResetEmail(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
120 			job.doUpdate();
121 		}
122 		return true;
123 	}
124 
125 	public boolean canFinish() {
126 		if (this.getContainer().getCurrentPage() == validatePage)
127 			return true;
128 		return false;
129 	}
130 
131 	private class ResetPassword {
132 		private char[] newPwd;
133 		private UserAdminWrapper userAdminWrapper;
134 		private List<User> usersToUpdate;
135 
136 		public ResetPassword(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, char[] newPwd) {
137 			this.newPwd = newPwd;
138 			this.usersToUpdate = usersToUpdate;
139 			this.userAdminWrapper = userAdminWrapper;
140 		}
141 
142 		@SuppressWarnings("unchecked")
143 		protected void doUpdate() {
144 			userAdminWrapper.beginTransactionIfNeeded();
145 			try {
146 				for (User user : usersToUpdate) {
147 					// the char array is emptied after being used.
148 					user.getCredentials().put(null, newPwd.clone());
149 				}
150 				userAdminWrapper.commitOrNotifyTransactionStateChange();
151 			} catch (Exception e) {
152 				throw new CmsException("Cannot perform batch update on users", e);
153 			} finally {
154 				UserTransaction ut = userAdminWrapper.getUserTransaction();
155 				try {
156 					if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
157 						ut.rollback();
158 				} catch (IllegalStateException | SecurityException | SystemException e) {
159 					log.error("Unable to rollback session in 'finally', " + "the system might be in a dirty state");
160 					e.printStackTrace();
161 				}
162 			}
163 		}
164 	}
165 
166 	private class ResetEmail {
167 		private String newEmail;
168 		private UserAdminWrapper userAdminWrapper;
169 		private List<User> usersToUpdate;
170 
171 		public ResetEmail(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, String newEmail) {
172 			this.newEmail = newEmail;
173 			this.usersToUpdate = usersToUpdate;
174 			this.userAdminWrapper = userAdminWrapper;
175 		}
176 
177 		@SuppressWarnings("unchecked")
178 		protected void doUpdate() {
179 			userAdminWrapper.beginTransactionIfNeeded();
180 			try {
181 				for (User user : usersToUpdate) {
182 					// the char array is emptied after being used.
183 					user.getProperties().put(LdapAttrs.mail.name(), newEmail);
184 				}
185 
186 				userAdminWrapper.commitOrNotifyTransactionStateChange();
187 				if (!usersToUpdate.isEmpty())
188 					userAdminWrapper.notifyListeners(
189 							new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, usersToUpdate.get(0)));
190 			} catch (Exception e) {
191 				throw new CmsException("Cannot perform batch update on users", e);
192 			} finally {
193 				UserTransaction ut = userAdminWrapper.getUserTransaction();
194 				try {
195 					if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
196 						ut.rollback();
197 				} catch (IllegalStateException | SecurityException | SystemException e) {
198 					log.error("Unable to rollback session in finally block, the system might be in a dirty state");
199 					e.printStackTrace();
200 				}
201 			}
202 		}
203 	}
204 
205 	// @SuppressWarnings("unused")
206 	// private class AddToGroup extends UpdateJob {
207 	// private String groupID;
208 	// private Session session;
209 	//
210 	// public AddToGroup(Session session, List<Node> nodesToUpdate,
211 	// String groupID) {
212 	// super(session, nodesToUpdate);
213 	// this.session = session;
214 	// this.groupID = groupID;
215 	// }
216 	//
217 	// protected void doUpdate(Node node) {
218 	// log.info("Add/Remove to group actions are not yet implemented");
219 	// // TODO implement this
220 	// // try {
221 	// // throw new CmsException("Not yet implemented");
222 	// // } catch (RepositoryException re) {
223 	// // throw new CmsException(
224 	// // "Unable to update boolean value for node " + node, re);
225 	// // }
226 	// }
227 	// }
228 
229 	// /**
230 	// * Base privileged job that will be run asynchronously to perform the
231 	// batch
232 	// * update
233 	// */
234 	// private abstract class UpdateJob extends PrivilegedJob {
235 	//
236 	// private final UserAdminWrapper userAdminWrapper;
237 	// private final List<User> usersToUpdate;
238 	//
239 	// protected abstract void doUpdate(User user);
240 	//
241 	// public UpdateJob(UserAdminWrapper userAdminWrapper,
242 	// List<User> usersToUpdate) {
243 	// super("Perform update");
244 	// this.usersToUpdate = usersToUpdate;
245 	// this.userAdminWrapper = userAdminWrapper;
246 	// }
247 	//
248 	// @Override
249 	// protected IStatus doRun(IProgressMonitor progressMonitor) {
250 	// try {
251 	// JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
252 	// int total = usersToUpdate.size();
253 	// monitor.beginTask("Performing change", total);
254 	// userAdminWrapper.beginTransactionIfNeeded();
255 	// for (User user : usersToUpdate) {
256 	// doUpdate(user);
257 	// monitor.worked(1);
258 	// }
259 	// userAdminWrapper.getUserTransaction().commit();
260 	// } catch (Exception e) {
261 	// throw new CmsException(
262 	// "Cannot perform batch update on users", e);
263 	// } finally {
264 	// UserTransaction ut = userAdminWrapper.getUserTransaction();
265 	// try {
266 	// if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
267 	// ut.rollback();
268 	// } catch (IllegalStateException | SecurityException
269 	// | SystemException e) {
270 	// log.error("Unable to rollback session in 'finally', "
271 	// + "the system might be in a dirty state");
272 	// e.printStackTrace();
273 	// }
274 	// }
275 	// return Status.OK_STATUS;
276 	// }
277 	// }
278 
279 	// PAGES
280 	/**
281 	 * Displays a combo box that enables user to choose which action to perform
282 	 */
283 	private class ChooseCommandWizardPage extends WizardPage {
284 		private static final long serialVersionUID = -8069434295293996633L;
285 		private Combo chooseCommandCmb;
286 		private Button trueChk;
287 		private Text valueTxt;
288 		private Text pwdTxt;
289 		private Text pwd2Txt;
290 
291 		public ChooseCommandWizardPage() {
292 			super("Choose a command to run.");
293 			setTitle("Choose a command to run.");
294 		}
295 
296 		@Override
297 		public void createControl(Composite parent) {
298 			GridLayout gl = new GridLayout();
299 			Composite container = new Composite(parent, SWT.NO_FOCUS);
300 			container.setLayout(gl);
301 
302 			chooseCommandCmb = new Combo(container, SWT.READ_ONLY);
303 			chooseCommandCmb.setLayoutData(EclipseUiUtils.fillWidth());
304 			String[] values = commands.keySet().toArray(new String[0]);
305 			chooseCommandCmb.setItems(values);
306 
307 			final Composite bottomPart = new Composite(container, SWT.NO_FOCUS);
308 			bottomPart.setLayoutData(EclipseUiUtils.fillAll());
309 			bottomPart.setLayout(EclipseUiUtils.noSpaceGridLayout());
310 
311 			chooseCommandCmb.addSelectionListener(new SelectionAdapter() {
312 				private static final long serialVersionUID = 1L;
313 
314 				@Override
315 				public void widgetSelected(SelectionEvent e) {
316 					if (getCommand().equals(CMD_UPDATE_PASSWORD))
317 						populatePasswordCmp(bottomPart);
318 					else if (getCommand().equals(CMD_UPDATE_EMAIL))
319 						populateEmailCmp(bottomPart);
320 					else if (getCommand().equals(CMD_GROUP_MEMBERSHIP))
321 						populateGroupCmp(bottomPart);
322 					else
323 						populateBooleanFlagCmp(bottomPart);
324 					checkPageComplete();
325 					bottomPart.layout(true, true);
326 				}
327 			});
328 			setControl(container);
329 		}
330 
331 		private void populateBooleanFlagCmp(Composite parent) {
332 			EclipseUiUtils.clear(parent);
333 			trueChk = new Button(parent, SWT.CHECK);
334 			trueChk.setText("Do it. (It will to the contrary if unchecked)");
335 			trueChk.setSelection(true);
336 			trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
337 		}
338 
339 		private void populatePasswordCmp(Composite parent) {
340 			EclipseUiUtils.clear(parent);
341 			Composite body = new Composite(parent, SWT.NO_FOCUS);
342 
343 			ModifyListener ml = new ModifyListener() {
344 				private static final long serialVersionUID = -1558726363536729634L;
345 
346 				@Override
347 				public void modifyText(ModifyEvent event) {
348 					checkPageComplete();
349 				}
350 			};
351 
352 			body.setLayout(new GridLayout(2, false));
353 			body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
354 			pwdTxt = EclipseUiUtils.createGridLP(body, "New password", ml);
355 			pwd2Txt = EclipseUiUtils.createGridLP(body, "Repeat password", ml);
356 		}
357 
358 		private void populateEmailCmp(Composite parent) {
359 			EclipseUiUtils.clear(parent);
360 			Composite body = new Composite(parent, SWT.NO_FOCUS);
361 
362 			ModifyListener ml = new ModifyListener() {
363 				private static final long serialVersionUID = 2147704227294268317L;
364 
365 				@Override
366 				public void modifyText(ModifyEvent event) {
367 					checkPageComplete();
368 				}
369 			};
370 
371 			body.setLayout(new GridLayout(2, false));
372 			body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
373 			valueTxt = EclipseUiUtils.createGridLT(body, "New e-mail", ml);
374 		}
375 
376 		private void checkPageComplete() {
377 			String errorMsg = null;
378 			if (chooseCommandCmb.getSelectionIndex() < 0)
379 				errorMsg = "Please select an action";
380 			else if (CMD_UPDATE_EMAIL.equals(getCommand())) {
381 				if (!valueTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
382 					errorMsg = "Not a valid e-mail address";
383 			} else if (CMD_UPDATE_PASSWORD.equals(getCommand())) {
384 				if (EclipseUiUtils.isEmpty(pwdTxt.getText()) || pwdTxt.getText().length() < 4)
385 					errorMsg = "Please enter a password that is at least 4 character long";
386 				else if (!pwdTxt.getText().equals(pwd2Txt.getText()))
387 					errorMsg = "Passwords are different";
388 			}
389 			if (EclipseUiUtils.notEmpty(errorMsg)) {
390 				setMessage(errorMsg, WizardPage.ERROR);
391 				setPageComplete(false);
392 			} else {
393 				setMessage("Page complete, you can proceed to user choice", WizardPage.INFORMATION);
394 				setPageComplete(true);
395 			}
396 
397 			getContainer().updateButtons();
398 		}
399 
400 		private void populateGroupCmp(Composite parent) {
401 			EclipseUiUtils.clear(parent);
402 			trueChk = new Button(parent, SWT.CHECK);
403 			trueChk.setText("Add to group. (It will remove user(s) from the " + "corresponding group if unchecked)");
404 			trueChk.setSelection(true);
405 			trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
406 		}
407 
408 		protected String getCommand() {
409 			return commands.get(chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex()));
410 		}
411 
412 		protected String getCommandLbl() {
413 			return chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex());
414 		}
415 
416 		@SuppressWarnings("unused")
417 		protected boolean getBoleanValue() {
418 			// FIXME this is not consistent and will lead to errors.
419 			if ("argeo:enabled".equals(getCommand()))
420 				return trueChk.getSelection();
421 			else
422 				return !trueChk.getSelection();
423 		}
424 
425 		@SuppressWarnings("unused")
426 		protected String getStringValue() {
427 			String value = null;
428 			if (valueTxt != null) {
429 				value = valueTxt.getText();
430 				if ("".equals(value.trim()))
431 					value = null;
432 			}
433 			return value;
434 		}
435 
436 		protected char[] getPwdValue() {
437 			// We do not directly reset the password text fields: There is no
438 			// need to over secure this process: setting a pwd to multi users
439 			// at the same time is anyhow a bad practice and should be used only
440 			// in test environment or for temporary access
441 			if (pwdTxt == null || pwdTxt.isDisposed())
442 				return null;
443 			else
444 				return pwdTxt.getText().toCharArray();
445 		}
446 
447 		protected String getEmailValue() {
448 			// We do not directly reset the password text fields: There is no
449 			// need to over secure this process: setting a pwd to multi users
450 			// at the same time is anyhow a bad practice and should be used only
451 			// in test environment or for temporary access
452 			if (valueTxt == null || valueTxt.isDisposed())
453 				return null;
454 			else
455 				return valueTxt.getText();
456 		}
457 	}
458 
459 	/**
460 	 * Displays a list of users with a check box to be able to choose some of
461 	 * them
462 	 */
463 	private class ChooseUsersWizardPage extends WizardPage implements IPageChangedListener {
464 		private static final long serialVersionUID = 7651807402211214274L;
465 		private ChooseUserTableViewer userTableCmp;
466 
467 		public ChooseUsersWizardPage() {
468 			super("Choose Users");
469 			setTitle("Select users who will be impacted");
470 		}
471 
472 		@Override
473 		public void createControl(Composite parent) {
474 			Composite pageCmp = new Composite(parent, SWT.NONE);
475 			pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
476 
477 			// Define the displayed columns
478 			List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
479 			columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
480 			columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
481 			columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
482 
483 			// Only show technical DN to admin
484 			if (CurrentUser.isInRole(NodeConstants.ROLE_ADMIN))
485 				columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
486 
487 			userTableCmp = new ChooseUserTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
488 			userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
489 			userTableCmp.setColumnDefinitions(columnDefs);
490 			userTableCmp.populate(true, true);
491 			userTableCmp.refresh();
492 
493 			setControl(pageCmp);
494 
495 			// Add listener to update message when shown
496 			final IWizardContainer wContainer = this.getContainer();
497 			if (wContainer instanceof IPageChangeProvider) {
498 				((IPageChangeProvider) wContainer).addPageChangedListener(this);
499 			}
500 
501 		}
502 
503 		@Override
504 		public void pageChanged(PageChangedEvent event) {
505 			if (event.getSelectedPage() == this) {
506 				String msg = "Chosen batch action: " + chooseCommandPage.getCommandLbl();
507 				((WizardPage) event.getSelectedPage()).setMessage(msg);
508 			}
509 		}
510 
511 		protected List<User> getSelectedUsers() {
512 			return userTableCmp.getSelectedUsers();
513 		}
514 
515 		private class ChooseUserTableViewer extends LdifUsersTable {
516 			private static final long serialVersionUID = 5080437561015853124L;
517 			private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.DN, LdapAttrs.cn.name(),
518 					LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
519 
520 			public ChooseUserTableViewer(Composite parent, int style) {
521 				super(parent, style);
522 			}
523 
524 			@Override
525 			protected List<User> listFilteredElements(String filter) {
526 				Role[] roles;
527 
528 				try {
529 					StringBuilder builder = new StringBuilder();
530 
531 					StringBuilder tmpBuilder = new StringBuilder();
532 					if (EclipseUiUtils.notEmpty(filter))
533 						for (String prop : knownProps) {
534 							tmpBuilder.append("(");
535 							tmpBuilder.append(prop);
536 							tmpBuilder.append("=*");
537 							tmpBuilder.append(filter);
538 							tmpBuilder.append("*)");
539 						}
540 					if (tmpBuilder.length() > 1) {
541 						builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
542 								.append(LdapObjs.inetOrgPerson.name()).append(")(|");
543 						builder.append(tmpBuilder.toString());
544 						builder.append("))");
545 					} else
546 						builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
547 								.append(LdapObjs.inetOrgPerson.name()).append(")");
548 					roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
549 				} catch (InvalidSyntaxException e) {
550 					throw new CmsException("Unable to get roles with filter: " + filter, e);
551 				}
552 				List<User> users = new ArrayList<User>();
553 				for (Role role : roles)
554 					// Prevent current logged in user to perform batch on
555 					// himself
556 					if (!UserAdminUtils.isCurrentUser((User) role))
557 						users.add((User) role);
558 				return users;
559 			}
560 		}
561 	}
562 
563 	/** Summary of input data before launching the process */
564 	private class ValidateAndLaunchWizardPage extends WizardPage implements IPageChangedListener {
565 		private static final long serialVersionUID = 7098918351451743853L;
566 		private ChosenUsersTableViewer userTableCmp;
567 
568 		public ValidateAndLaunchWizardPage() {
569 			super("Validate and launch");
570 			setTitle("Validate and launch");
571 		}
572 
573 		@Override
574 		public void createControl(Composite parent) {
575 			Composite pageCmp = new Composite(parent, SWT.NO_FOCUS);
576 			pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
577 
578 			List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
579 			columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
580 			columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
581 			columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
582 			// Only show technical DN to admin
583 			if (CurrentUser.isInRole(NodeConstants.ROLE_ADMIN))
584 				columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
585 			userTableCmp = new ChosenUsersTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
586 			userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
587 			userTableCmp.setColumnDefinitions(columnDefs);
588 			userTableCmp.populate(false, false);
589 			userTableCmp.refresh();
590 			setControl(pageCmp);
591 			// Add listener to update message when shown
592 			final IWizardContainer wContainer = this.getContainer();
593 			if (wContainer instanceof IPageChangeProvider) {
594 				((IPageChangeProvider) wContainer).addPageChangedListener(this);
595 			}
596 		}
597 
598 		@Override
599 		public void pageChanged(PageChangedEvent event) {
600 			if (event.getSelectedPage() == this) {
601 				@SuppressWarnings({ "unchecked", "rawtypes" })
602 				Object[] values = ((ArrayList) userListPage.getSelectedUsers())
603 						.toArray(new Object[userListPage.getSelectedUsers().size()]);
604 				userTableCmp.getTableViewer().setInput(values);
605 				String msg = "Following batch action: [" + chooseCommandPage.getCommandLbl()
606 						+ "] will be perfomed on the users listed below.\n";
607 				// + "Are you sure you want to proceed?";
608 				setMessage(msg);
609 			}
610 		}
611 
612 		private class ChosenUsersTableViewer extends LdifUsersTable {
613 			private static final long serialVersionUID = 7814764735794270541L;
614 
615 			public ChosenUsersTableViewer(Composite parent, int style) {
616 				super(parent, style);
617 			}
618 
619 			@Override
620 			protected List<User> listFilteredElements(String filter) {
621 				return userListPage.getSelectedUsers();
622 			}
623 		}
624 	}
625 }