]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java
Move most of the code to the internal packages
[lgpl/argeo-commons.git] / org.argeo.security.ui.admin / src / org / argeo / security / ui / admin / internal / parts / UserBatchUpdateWizard.java
diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java
new file mode 100644 (file)
index 0000000..aa6e2c6
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.ui.admin.internal.parts;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.version.VersionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.ArgeoMonitor;
+import org.argeo.eclipse.ui.EclipseArgeoMonitor;
+import org.argeo.eclipse.ui.parts.UsersTable;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrUserDetails;
+import org.argeo.security.ui.PrivilegedJob;
+import org.argeo.security.ui.admin.SecurityAdminPlugin;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Wizard to update users */
+public class UserBatchUpdateWizard extends Wizard {
+       private final static Log log = LogFactory
+                       .getLog(UserBatchUpdateWizard.class);
+       private Session session;
+       private UserAdminService userAdminService;
+
+       // pages
+       private ChooseCommandWizardPage chooseCommandPage;
+       private ChooseUsersWizardPage userListPage;
+       private ValidateAndLaunchWizardPage validatePage;
+
+       // /////////////////////////////////////////////////
+       // / Definition of the various implemented commands
+       private final static String CMD_UPDATE_PASSWORD = "resetPassword";
+       private final static String CMD_GROUP_MEMBERSHIP = "groupMembership";
+
+       private final Map<String, String> commands = new HashMap<String, String>() {
+               private static final long serialVersionUID = 1L;
+               {
+                       put("Enable user(s)", ArgeoNames.ARGEO_ENABLED);
+                       put("Expire credentials", ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED);
+                       put("Expire account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED);
+                       put("Lock account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED);
+                       put("Reset password(s)", CMD_UPDATE_PASSWORD);
+                       // TODO implement role / group management
+                       // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP);
+               }
+       };
+
+       public UserBatchUpdateWizard(Session session,
+                       UserAdminService userAdminService) {
+               this.session = session;
+               this.userAdminService = userAdminService;
+       }
+
+       @Override
+       public void addPages() {
+               chooseCommandPage = new ChooseCommandWizardPage();
+               addPage(chooseCommandPage);
+               userListPage = new ChooseUsersWizardPage(session);
+               addPage(userListPage);
+               validatePage = new ValidateAndLaunchWizardPage(session);
+               addPage(validatePage);
+       }
+
+       @Override
+       public boolean performFinish() {
+               if (!canFinish())
+                       return false;
+
+               UpdateJob job = null;
+               if (ArgeoNames.ARGEO_ENABLED.equals(chooseCommandPage.getCommand())) {
+                       job = new UpdateBoolean(session, userListPage.getSelectedUsers(),
+                                       ArgeoNames.ARGEO_ENABLED,
+                                       chooseCommandPage.getBoleanValue());
+               } else if (ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED
+                               .equals(chooseCommandPage.getCommand())) {
+                       job = new UpdateBoolean(session, userListPage.getSelectedUsers(),
+                                       ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED,
+                                       chooseCommandPage.getBoleanValue());
+               } else if (ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED
+                               .equals(chooseCommandPage.getCommand())) {
+                       job = new UpdateBoolean(session, userListPage.getSelectedUsers(),
+                                       ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED,
+                                       chooseCommandPage.getBoleanValue());
+               } else if (ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED.equals(chooseCommandPage
+                               .getCommand())) {
+                       job = new UpdateBoolean(session, userListPage.getSelectedUsers(),
+                                       ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED,
+                                       chooseCommandPage.getBoleanValue());
+               } else if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) {
+                       String newValue = chooseCommandPage.getPwdValue();
+                       if (newValue == null)
+                               throw new ArgeoException(
+                                               "Password cannot be null or an empty string");
+                       job = new ResetPassword(session, userAdminService,
+                                       userListPage.getSelectedUsers(), newValue);
+               }
+
+               if (job != null)
+                       job.schedule();
+               return true;
+       }
+
+       public void setSession(Session session) {
+               this.session = session;
+       }
+
+       public boolean canFinish() {
+               if (this.getContainer().getCurrentPage() == validatePage)
+                       return true;
+               return false;
+       }
+
+       // /////////////////////////
+       // REEL UPDATE JOB
+       private class UpdateBoolean extends UpdateJob {
+               private String propertyName;
+               private boolean value;
+
+               public UpdateBoolean(Session session, List<Node> nodesToUpdate,
+                               String propertyName, boolean value) {
+                       super(session, nodesToUpdate);
+                       this.propertyName = propertyName;
+                       this.value = value;
+               }
+
+               protected void doUpdate(Node node) {
+                       try {
+                               node.setProperty(propertyName, value);
+                       } catch (RepositoryException re) {
+                               throw new ArgeoException(
+                                               "Unable to update boolean value for node " + node, re);
+                       }
+               }
+       }
+
+       private class ResetPassword extends UpdateJob {
+               private String newValue;
+               private UserAdminService userAdminService;
+
+               public ResetPassword(Session session,
+                               UserAdminService userAdminService, List<Node> nodesToUpdate,
+                               String newValue) {
+                       super(session, nodesToUpdate);
+                       this.newValue = newValue;
+                       this.userAdminService = userAdminService;
+               }
+
+               protected void doUpdate(Node node) {
+                       try {
+                               String userId = node.getProperty(ArgeoNames.ARGEO_USER_ID)
+                                               .getString();
+                               if (userAdminService.userExists(userId)) {
+                                       JcrUserDetails userDetails = (JcrUserDetails) userAdminService
+                                                       .loadUserByUsername(userId);
+                                       userAdminService.updateUser(userDetails
+                                                       .cloneWithNewPassword(newValue));
+                               }
+                       } catch (RepositoryException re) {
+                               throw new ArgeoException(
+                                               "Unable to update boolean value for node " + node, re);
+                       }
+               }
+       }
+
+       @SuppressWarnings("unused")
+       private class AddToGroup extends UpdateJob {
+               private String groupID;
+               private Session session;
+
+               public AddToGroup(Session session, List<Node> nodesToUpdate,
+                               String groupID) {
+                       super(session, nodesToUpdate);
+                       this.session = session;
+                       this.groupID = groupID;
+               }
+
+               protected void doUpdate(Node node) {
+                       log.info("Add/Remove to group actions are not yet implemented");
+                       // TODO implement this
+                       // try {
+                       // throw new ArgeoException("Not yet implemented");
+                       // } catch (RepositoryException re) {
+                       // throw new ArgeoException(
+                       // "Unable to update boolean value for node " + node, re);
+                       // }
+               }
+       }
+
+       /**
+        * Base privileged job that will be run asynchronously to perform the batch
+        * update
+        */
+       private abstract class UpdateJob extends PrivilegedJob {
+
+               private final Session currSession;
+               private final List<Node> nodesToUpdate;
+
+               protected abstract void doUpdate(Node node);
+
+               public UpdateJob(Session session, List<Node> nodesToUpdate) {
+                       super("Perform update");
+                       try {
+                               this.currSession = session.getRepository().login();
+                               // "move" nodes to update in the new session
+                               // the "old" session will be closed by the calling command
+                               // before the job has effectively ran
+                               // TODO there must be a cleaner way to do.
+                               List<Node> nodes = new ArrayList<Node>();
+                               for (Node node : nodesToUpdate) {
+                                       nodes.add(currSession.getNode(node.getPath()));
+                               }
+                               this.nodesToUpdate = nodes;
+                       } catch (RepositoryException e) {
+                               throw new ArgeoException("Error while dupplicating "
+                                               + "session for job", e);
+                       }
+               }
+
+               @Override
+               protected IStatus doRun(IProgressMonitor progressMonitor) {
+                       try {
+                               ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor);
+                               VersionManager vm = currSession.getWorkspace()
+                                               .getVersionManager();
+                               int total = nodesToUpdate.size();
+                               monitor.beginTask("Performing change", total);
+                               for (Node node : nodesToUpdate) {
+                                       String path = node.getPath();
+                                       vm.checkout(path);
+                                       doUpdate(node);
+                                       currSession.save();
+                                       vm.checkin(path);
+                                       monitor.worked(1);
+                               }
+                       } catch (Exception e) {
+                               log.error("Cannot perform batch update on users", e);
+                               // e.printStackTrace();
+
+                               // Dig exception to find the root cause that will enable the
+                               // user to understand the problem
+                               Throwable cause = e;
+                               Throwable originalCause = e;
+                               while (cause != null) {
+                                       if (log.isTraceEnabled())
+                                               log.trace("Parent Cause message : "
+                                                               + cause.getMessage());
+                                       originalCause = cause;
+                                       cause = cause.getCause();
+                               }
+                               return new Status(IStatus.ERROR, SecurityAdminPlugin.PLUGIN_ID,
+                                               "Cannot perform updates.", originalCause);
+                       } finally {
+                               JcrUtils.logoutQuietly(currSession);
+                       }
+                       return Status.OK_STATUS;
+               }
+       }
+
+       // //////////////////////
+       // Pages definition
+       /** Displays a combo box that enables user to choose which action to perform */
+       private class ChooseCommandWizardPage extends WizardPage {
+               private static final long serialVersionUID = 1L;
+
+               private Combo chooseCommandCmb;
+               private Button trueChk;
+               private Text valueTxt;
+               private Text pwdTxt;
+               private Text pwd2Txt;
+
+               public ChooseCommandWizardPage() {
+                       super("Choose a command to run.");
+                       setTitle("Choose a command to run.");
+               }
+
+               @Override
+               public void createControl(Composite parent) {
+                       GridLayout gl = new GridLayout();
+                       Composite container = new Composite(parent, SWT.NO_FOCUS);
+                       container.setLayout(gl);
+
+                       chooseCommandCmb = new Combo(container, SWT.NO_FOCUS);
+                       String[] values = commands.keySet().toArray(
+                                       new String[commands.size()]);
+                       chooseCommandCmb.setItems(values);
+                       chooseCommandCmb.setLayoutData(new GridData(SWT.FILL, SWT.TOP,
+                                       true, false));
+
+                       final Composite bottomPart = new Composite(container, SWT.NO_FOCUS);
+                       gl = new GridLayout();
+                       gl.horizontalSpacing = gl.marginWidth = gl.verticalSpacing = 0;
+                       bottomPart.setLayout(gl);
+                       bottomPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                                       true));
+
+                       chooseCommandCmb.addSelectionListener(new SelectionListener() {
+                               private static final long serialVersionUID = 1L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       if (getCommand().equals(CMD_UPDATE_PASSWORD))
+                                               populatePasswordCmp(bottomPart);
+                                       else if (getCommand().equals(CMD_GROUP_MEMBERSHIP))
+                                               populateGroupCmp(bottomPart);
+                                       else
+                                               populateBooleanFlagCmp(bottomPart);
+                                       bottomPart.pack(true);
+                                       bottomPart.layout();
+                               }
+
+                               @Override
+                               public void widgetDefaultSelected(SelectionEvent e) {
+                               }
+                       });
+
+                       setControl(container);
+               }
+
+               private void cleanParent(Composite parent) {
+                       if (parent.getChildren().length > 0) {
+                               for (Control control : parent.getChildren())
+                                       control.dispose();
+                       }
+               }
+
+               private void populateBooleanFlagCmp(Composite parent) {
+                       cleanParent(parent);
+                       trueChk = new Button(parent, SWT.CHECK);
+                       trueChk.setText("Do it. (It will to the contrary if unchecked)");
+                       trueChk.setSelection(true);
+                       trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+               }
+
+               private void populatePasswordCmp(Composite parent) {
+                       cleanParent(parent);
+                       Composite body = new Composite(parent, SWT.NO_FOCUS);
+                       body.setLayout(new GridLayout(2, false));
+                       body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+                       pwdTxt = createLP(body, "New password", "");
+                       pwd2Txt = createLP(body, "Repeat password", "");
+               }
+
+               /** Creates label and password. */
+               protected Text createLP(Composite body, String label, String value) {
+                       Label lbl = new Label(body, SWT.NONE);
+                       lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+                       lbl.setText(label);
+                       Text text = new Text(body, SWT.BORDER | SWT.PASSWORD);
+                       text.setText(value);
+                       text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+                       return text;
+               }
+
+               private void populateGroupCmp(Composite parent) {
+                       if (parent.getChildren().length > 0) {
+                               for (Control control : parent.getChildren())
+                                       control.dispose();
+                       }
+                       trueChk = new Button(parent, SWT.CHECK);
+                       trueChk.setText("Add to group. (It will remove user(s) from the "
+                                       + "corresponding group if unchecked)");
+                       trueChk.setSelection(true);
+                       trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+               }
+
+               protected String getCommand() {
+                       return commands.get(chooseCommandCmb.getItem(chooseCommandCmb
+                                       .getSelectionIndex()));
+               }
+
+               protected String getCommandLbl() {
+                       return chooseCommandCmb.getItem(chooseCommandCmb
+                                       .getSelectionIndex());
+               }
+
+               protected boolean getBoleanValue() {
+                       // FIXME this is not consistent and will lead to errors.
+                       if (ArgeoNames.ARGEO_ENABLED.equals(getCommand()))
+                               return trueChk.getSelection();
+                       else
+                               return !trueChk.getSelection();
+               }
+
+               @SuppressWarnings("unused")
+               protected String getStringValue() {
+                       String value = null;
+                       if (valueTxt != null) {
+                               value = valueTxt.getText();
+                               if ("".equals(value.trim()))
+                                       value = null;
+                       }
+                       return value;
+               }
+
+               protected String getPwdValue() {
+                       String newPwd = null;
+                       if (pwdTxt == null || pwd2Txt == null)
+                               return null;
+                       if (!pwdTxt.getText().equals("") || !pwd2Txt.getText().equals("")) {
+                               if (pwdTxt.getText().equals(pwd2Txt.getText())) {
+                                       newPwd = pwdTxt.getText();
+                                       pwdTxt.setText("");
+                                       pwd2Txt.setText("");
+                               } else {
+                                       pwdTxt.setText("");
+                                       pwd2Txt.setText("");
+                                       throw new ArgeoException("Passwords are not equals");
+                               }
+                       }
+                       return newPwd;
+               }
+       }
+
+       /**
+        * Displays a list of users with a check box to be able to choose some of
+        * them
+        */
+       private class ChooseUsersWizardPage extends WizardPage implements
+                       IPageChangedListener {
+               private static final long serialVersionUID = 1L;
+               private UsersTable userTableCmp;
+               private Composite container;
+               private Session session;
+
+               public ChooseUsersWizardPage(Session session) {
+                       super("Choose Users");
+                       this.session = session;
+                       setTitle("Select users who will be impacted");
+               }
+
+               @Override
+               public void createControl(Composite parent) {
+                       container = new Composite(parent, SWT.NONE);
+                       container.setLayout(new FillLayout());
+                       userTableCmp = new MyUserTableCmp(container, SWT.NO_FOCUS, session);
+                       userTableCmp.populate(true, true);
+                       setControl(container);
+
+                       // Add listener to update message when shown
+                       final IWizardContainer container = this.getContainer();
+                       if (container instanceof IPageChangeProvider) {
+                               ((IPageChangeProvider) container).addPageChangedListener(this);
+                       }
+
+               }
+
+               @Override
+               public void pageChanged(PageChangedEvent event) {
+                       if (event.getSelectedPage() == this) {
+                               String msg = "Chosen batch action: "
+                                               + chooseCommandPage.getCommandLbl();
+                               ((WizardPage) event.getSelectedPage()).setMessage(msg);
+                       }
+               }
+
+               protected List<Node> getSelectedUsers() {
+                       return userTableCmp.getSelectedUsers();
+               }
+
+               private class MyUserTableCmp extends UsersTable {
+
+                       private static final long serialVersionUID = 1L;
+
+                       public MyUserTableCmp(Composite parent, int style, Session session) {
+                               super(parent, style, session);
+                       }
+
+                       @Override
+                       protected void refreshFilteredList() {
+                               List<Node> nodes = new ArrayList<Node>();
+                               try {
+                                       NodeIterator ni = listFilteredElements(session,
+                                                       getFilterString());
+
+                                       users: while (ni.hasNext()) {
+                                               Node currNode = ni.nextNode();
+                                               String username = currNode.hasProperty(ARGEO_USER_ID) ? currNode
+                                                               .getProperty(ARGEO_USER_ID).getString() : "";
+                                               if (username.equals(session.getUserID()))
+                                                       continue users;
+                                               else
+                                                       nodes.add(currNode);
+                                       }
+                                       getTableViewer().setInput(nodes.toArray());
+                               } catch (RepositoryException e) {
+                                       throw new ArgeoException("Unable to list users", e);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Recapitulation of input data before running real update
+        */
+       private class ValidateAndLaunchWizardPage extends WizardPage implements
+                       IPageChangedListener {
+               private static final long serialVersionUID = 1L;
+               private UsersTable userTableCmp;
+               private Session session;
+
+               public ValidateAndLaunchWizardPage(Session session) {
+                       super("Validate and launch");
+                       this.session = session;
+                       setTitle("Validate and launch");
+               }
+
+               @Override
+               public void createControl(Composite parent) {
+                       Composite mainCmp = new Composite(parent, SWT.NO_FOCUS);
+                       mainCmp.setLayout(new FillLayout());
+
+                       // Add listener to update user list when shown
+                       final IWizardContainer container = this.getContainer();
+                       if (container instanceof IPageChangeProvider) {
+                               ((IPageChangeProvider) container).addPageChangedListener(this);
+                       }
+
+                       userTableCmp = new UsersTable(mainCmp, SWT.NO_FOCUS, session);
+                       userTableCmp.populate(false, false);
+                       setControl(mainCmp);
+               }
+
+               @Override
+               public void pageChanged(PageChangedEvent event) {
+                       if (event.getSelectedPage() == this) {
+                               @SuppressWarnings({ "unchecked", "rawtypes" })
+                               Object[] values = ((ArrayList) userListPage.getSelectedUsers())
+                                               .toArray(new Object[userListPage.getSelectedUsers()
+                                                               .size()]);
+                               userTableCmp.getTableViewer().setInput(values);
+                               String msg = "Following batch action: ["
+                                               + chooseCommandPage.getCommandLbl()
+                                               + "] will be perfomed on the users listed below.\n"
+                                               + "Are you sure you want to proceed?";
+                               ((WizardPage) event.getSelectedPage()).setMessage(msg);
+                       }
+               }
+
+               // private class MyUserTableCmp extends UserTableComposite {
+               // public MyUserTableCmp(Composite parent, int style, Session session) {
+               // super(parent, style, session);
+               // }
+               //
+               // @Override
+               // protected void refreshFilteredList() {
+               // @SuppressWarnings({ "unchecked", "rawtypes" })
+               //
+               // setFilteredList(values);
+               // }
+               //
+               // @Override
+               // public void setVisible(boolean visible) {
+               // super.setVisible(visible);
+               // if (visible)
+               // refreshFilteredList();
+               // }
+               // }
+       }
+}
\ No newline at end of file