--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Utilities to simplify UI development. */
+public class EclipseUiUtils {
+ /**
+ * Create a label and a text field for a grid layout, the text field grabing
+ * excess horizontal
+ *
+ * @param parent
+ * the parent composite
+ * @param label
+ * the lable to display
+ * @param modifyListener
+ * a {@link ModifyListener} to listen on events on the text, can
+ * be null
+ * @return the created text
+ */
+ public static Text createGridLT(Composite parent, String label,
+ ModifyListener modifyListener) {
+ Label lbl = new Label(parent, SWT.LEAD);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Text txt = new Text(parent, SWT.LEAD | SWT.BORDER);
+ txt.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+ if (txt != null)
+ txt.addModifyListener(modifyListener);
+ return txt;
+ }
+
+}
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean id="openArgeoUserEditor" class="org.argeo.security.ui.admin.commands.OpenArgeoUserEditor"
+ <bean id="openArgeoUserEditor"
+ class="org.argeo.security.ui.admin.commands.OpenArgeoUserEditor"
scope="prototype" />
- <bean id="newArgeoUserEditor" class="org.argeo.security.ui.admin.commands.OpenArgeoUserEditor"
+ <bean id="newArgeoUserEditor" class="org.argeo.security.ui.admin.commands.NewUser"
scope="prototype" />
<bean id="addRole" class="org.argeo.security.ui.admin.commands.AddRole"
scope="prototype">
--- /dev/null
+package org.argeo.security.ui.admin.commands;
+
+import org.argeo.security.ui.admin.wizards.NewUserWizard;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/** Command handler to set visible or open a Argeo user. */
+public class NewUser extends AbstractHandler {
+
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ try {
+ NewUserWizard newUserWizard = new NewUserWizard();
+ WizardDialog dialog = new WizardDialog(
+ HandlerUtil.getActiveShell(event), newUserWizard);
+ dialog.open();
+ } catch (Exception e) {
+ throw new ExecutionException("Cannot open editor", e);
+ }
+ return null;
+ }
+}
--- /dev/null
+package org.argeo.security.ui.admin.wizards;
+
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.security.UserAdminService;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class MainUserInfoWizardPage extends WizardPage implements
+ ModifyListener {
+ private Text username, firstName, lastName, primaryEmail;
+
+ public MainUserInfoWizardPage() {
+ super("Main");
+ setTitle("Required Information");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ parent.setLayout(new FillLayout());
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ username = EclipseUiUtils.createGridLT(composite, "Username", this);
+ primaryEmail = EclipseUiUtils.createGridLT(composite, "Email", this);
+ firstName = EclipseUiUtils.createGridLT(composite, "First name", this);
+ lastName = EclipseUiUtils.createGridLT(composite, "Last name", this);
+ setControl(composite);
+ }
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String message = checkComplete();
+ if (message != null)
+ setMessage(message, WizardPage.ERROR);
+ else {
+ setMessage("Complete", WizardPage.INFORMATION);
+ setPageComplete(true);
+ }
+ }
+
+ /** @return error message or null if complete */
+ protected String checkComplete() {
+ if (!username.getText().matches(UserAdminService.USERNAME_PATTERN))
+ return "Wrong user name format, should be lower case, between 3 and 15 characters with only '_' as acceptable special character.";
+ if (!primaryEmail.getText().matches(UserAdminService.EMAIL_PATTERN))
+ return "Not a valid email address";
+ if (firstName.getText().trim().equals(""))
+ return "Specify a first name";
+ if (lastName.getText().trim().equals(""))
+ return "Specify a last name";
+ return null;
+ }
+
+ @Override
+ public boolean canFlipToNextPage() {
+ // TODO Auto-generated method stub
+ return super.canFlipToNextPage();
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ // TODO Auto-generated method stub
+ return super.isPageComplete();
+ }
+
+}
--- /dev/null
+package org.argeo.security.ui.admin.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+
+public class NewUserWizard extends Wizard {
+ private MainUserInfoWizardPage mainUserInfo;
+
+ @Override
+ public void addPages() {
+ mainUserInfo = new MainUserInfoWizardPage();
+ addPage(mainUserInfo);
+ }
+
+ @Override
+ public boolean performFinish() {
+ return false;
+ }
+
+}
import java.util.Set;
public interface UserAdminService {
+ /**
+ * Usernames must match this regexp pattern ({@value #USERNAME_PATTERN}).
+ * Thanks to <a href=
+ * "http://www.mkyong.com/regular-expressions/how-to-validate-username-with-regular-expression/"
+ * >this tip</a> (modified to remove '-')
+ */
+ public final static String USERNAME_PATTERN = "^[a-z0-9_]{3,15}$";
+
+ /**
+ * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}.
+ * Thanks to <a href=
+ * "http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/"
+ * >this tip</a>.
+ */
+ public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
+
/*
* USERS
*/
if (SecurityContextHolder.getContext().getAuthentication() == null) {
// authentication
- systemExecutor.execute(action);
- JcrUtils.logoutQuietly(session);
+ try {
+ systemExecutor.execute(action);
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
} else {
// authenticated user
action.run();
if (log.isDebugEnabled())
log.debug("Mapped " + ctx.getDn() + " to " + userProfile);
return userHomePath;
- } catch (RepositoryException e) {
+ } catch (Exception e) {
JcrUtils.discardQuietly(session);
throw new ArgeoException("Cannot synchronize JCR and LDAP", e);
} finally {
/** Logs in to the repository using various strategies. */
protected Session login() {
- // discard sesison previoussly attached to this thread
+ if (!isActive())
+ throw new ArgeoException("Thread bound session factory inactive");
+
+ // discard session previously attached to this thread
Thread thread = Thread.currentThread();
if (activeSessions.containsKey(thread.getId())) {
Session oldSession = activeSessions.remove(thread.getId());
}
public synchronized void destroy() throws Exception {
+ if (activeSessions.size() == 0)
+ return;
+
if (log.isDebugEnabled())
log.debug("Cleaning up " + activeSessions.size()
+ " active JCR sessions...");
sess.logout();
}
activeSessions.clear();
- monitoringThread.join(1000);
}
protected Boolean isActive() {
notifyAll();
}
+ protected synchronized void removeSession(Thread thread) {
+ if (!isActive())
+ return;
+ activeSessions.remove(thread.getId());
+ threads.remove(thread);
+ }
+
+ protected synchronized void cleanDeadThreads() {
+ if (!isActive())
+ return;
+ Iterator<Thread> it = threads.iterator();
+ while (it.hasNext()) {
+ Thread thread = it.next();
+ if (!thread.isAlive() && isActive()) {
+ if (activeSessions.containsKey(thread.getId())) {
+ Session session = activeSessions.get(thread.getId());
+ activeSessions.remove(thread.getId());
+ session.logout();
+ if (log.isDebugEnabled())
+ log.debug("Cleaned up JCR session (userID="
+ + session.getUserID() + ") from dead thread "
+ + thread.getId());
+ }
+ it.remove();
+ }
+ }
+ try {
+ wait(1000);
+ } catch (InterruptedException e) {
+ // silent
+ }
+ }
+
public Class<? extends Session> getObjectType() {
return Session.class;
}
Object ret = method.invoke(threadSession, args);
if ("logout".equals(method.getName())) {
- synchronized (ThreadBoundJcrSessionFactory.this) {
- session.remove();
- Thread thread = Thread.currentThread();
- if (isActive()) {
- activeSessions.remove(thread.getId());
- threads.remove(thread);
- }
- if (log.isTraceEnabled())
- log.trace("Logged out JCR session (userId="
- + threadSession.getUserID() + ") on thread "
- + thread.getId());
- }
+ session.remove();
+ Thread thread = Thread.currentThread();
+ removeSession(thread);
+ if (log.isTraceEnabled())
+ log.trace("Logged out JCR session (userId="
+ + threadSession.getUserID() + ") on thread "
+ + thread.getId());
}
return ret;
}
@Override
public void run() {
while (isActive()) {
- Iterator<Thread> it = threads.iterator();
- while (it.hasNext()) {
- Thread thread = it.next();
- if (!thread.isAlive() && isActive()) {
- if (activeSessions.containsKey(thread.getId())) {
- Session session = activeSessions
- .get(thread.getId());
- activeSessions.remove(thread.getId());
- session.logout();
- if (log.isDebugEnabled())
- log.debug("Cleaned up JCR session (userID="
- + session.getUserID()
- + ") from dead thread "
- + thread.getId());
- }
- it.remove();
- }
- }
-
- synchronized (ThreadBoundJcrSessionFactory.this) {
- try {
- ThreadBoundJcrSessionFactory.this.wait(1000);
- } catch (InterruptedException e) {
- // silent
- }
- }
+ cleanDeadThreads();
}
}