]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java
Bug 28
[lgpl/argeo-commons.git] / security / plugins / org.argeo.security.ui.admin / src / main / java / org / argeo / security / ui / admin / views / UsersView.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.security.ui.admin.views;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import javax.jcr.Node;
22 import javax.jcr.NodeIterator;
23 import javax.jcr.Property;
24 import javax.jcr.RepositoryException;
25 import javax.jcr.Session;
26 import javax.jcr.observation.Event;
27 import javax.jcr.observation.EventIterator;
28 import javax.jcr.observation.EventListener;
29 import javax.jcr.query.QueryManager;
30 import javax.jcr.query.QueryResult;
31 import javax.jcr.query.qom.Constraint;
32 import javax.jcr.query.qom.DynamicOperand;
33 import javax.jcr.query.qom.Ordering;
34 import javax.jcr.query.qom.QueryObjectModel;
35 import javax.jcr.query.qom.QueryObjectModelFactory;
36 import javax.jcr.query.qom.Selector;
37 import javax.jcr.query.qom.StaticOperand;
38
39 import org.argeo.ArgeoException;
40 import org.argeo.eclipse.ui.EclipseUiUtils;
41 import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
42 import org.argeo.eclipse.ui.utils.CommandUtils;
43 import org.argeo.jcr.ArgeoJcrConstants;
44 import org.argeo.jcr.ArgeoNames;
45 import org.argeo.jcr.ArgeoTypes;
46 import org.argeo.jcr.JcrUtils;
47 import org.argeo.security.ui.admin.SecurityAdminPlugin;
48 import org.argeo.security.ui.admin.commands.OpenArgeoUserEditor;
49 import org.eclipse.jface.viewers.ColumnLabelProvider;
50 import org.eclipse.jface.viewers.DoubleClickEvent;
51 import org.eclipse.jface.viewers.IDoubleClickListener;
52 import org.eclipse.jface.viewers.IStructuredContentProvider;
53 import org.eclipse.jface.viewers.IStructuredSelection;
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.swt.SWT;
59 import org.eclipse.swt.events.ModifyEvent;
60 import org.eclipse.swt.events.ModifyListener;
61 import org.eclipse.swt.events.SelectionAdapter;
62 import org.eclipse.swt.events.SelectionEvent;
63 import org.eclipse.swt.events.SelectionListener;
64 import org.eclipse.swt.graphics.Font;
65 import org.eclipse.swt.graphics.Image;
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.Composite;
70 import org.eclipse.swt.widgets.Table;
71 import org.eclipse.swt.widgets.Text;
72 import org.eclipse.ui.part.ViewPart;
73
74 /** List all users. */
75 public class UsersView extends ViewPart implements ArgeoNames {
76 public final static String ID = SecurityAdminPlugin.PLUGIN_ID
77 + ".adminUsersView";
78
79 private TableViewer viewer;
80 private Text filterTxt;
81 private final static String FILTER_HELP_MSG = "Type filter criterion "
82 + "separated by a space (on user ID, name and E-mail)";
83 private final static Image FILTER_RESET = SecurityAdminPlugin
84 .getImageDescriptor("icons/clear.gif").createImage();
85
86 private Session session;
87
88 private UserStructureListener userStructureListener;
89 private UserPropertiesListener userPropertiesListener;
90
91 private Font italic;
92 private Font bold;
93
94 @Override
95 public void createPartControl(Composite parent) {
96 italic = EclipseUiUtils.getItalicFont(parent);
97 bold = EclipseUiUtils.getBoldFont(parent);
98
99 // Main Layout
100 GridLayout layout = new GridLayout(1, false);
101 parent.setLayout(layout);
102 createFilterPart(parent);
103
104 viewer = createTableViewer(parent);
105 EclipseUiSpecificUtils.enableToolTipSupport(viewer);
106 viewer.setContentProvider(new UsersContentProvider());
107 viewer.addDoubleClickListener(new ViewDoubleClickListener());
108 getViewSite().setSelectionProvider(viewer);
109
110 userStructureListener = new UserStructureListener();
111 JcrUtils.addListener(session, userStructureListener, Event.NODE_ADDED
112 | Event.NODE_REMOVED, ArgeoJcrConstants.PEOPLE_BASE_PATH, null);
113 userPropertiesListener = new UserPropertiesListener();
114 JcrUtils.addListener(session, userStructureListener,
115 Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED
116 | Event.PROPERTY_REMOVED,
117 ArgeoJcrConstants.PEOPLE_BASE_PATH,
118 ArgeoTypes.ARGEO_USER_PROFILE);
119
120 refreshFilteredList();
121 }
122
123 protected TableViewer createTableViewer(final Composite parent) {
124
125 Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
126 GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
127 gd.grabExcessHorizontalSpace = true;
128 gd.grabExcessVerticalSpace = true;
129 table.setLayoutData(gd);
130
131 TableViewer viewer = new TableViewer(table);
132 table.setLinesVisible(true);
133 table.setHeaderVisible(true);
134
135 // pass a mapping between col index and property name to the comparator.
136 List<String> propertiesList = new ArrayList<String>();
137
138 // User ID
139 TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
140 column.getColumn().setText("User ID");
141 column.getColumn().setWidth(100);
142 column.getColumn().addSelectionListener(getSelectionAdapter(0));
143 propertiesList.add(ARGEO_USER_ID);
144 column.setLabelProvider(new CLProvider() {
145 public String getText(Object elem) {
146 return getProperty(elem, ARGEO_USER_ID);
147 // if (username.equals(session.getUserID()))
148 // return "[" + username + "]";
149 // else
150 // return username;
151 }
152 });
153
154 // Displayed name
155 column = new TableViewerColumn(viewer, SWT.NONE);
156 column.getColumn().setText("Name");
157 column.getColumn().setWidth(150);
158 column.getColumn().addSelectionListener(getSelectionAdapter(1));
159 propertiesList.add(Property.JCR_TITLE);
160 column.setLabelProvider(new CLProvider() {
161 public String getText(Object elem) {
162 return getProperty(elem, Property.JCR_TITLE);
163 }
164 });
165
166 // E-mail
167 column = new TableViewerColumn(viewer, SWT.NONE);
168 column.getColumn().setText("E-mail");
169 column.getColumn().setWidth(150);
170 column.getColumn().addSelectionListener(getSelectionAdapter(2));
171 propertiesList.add(ARGEO_PRIMARY_EMAIL);
172 column.setLabelProvider(new CLProvider() {
173 public String getText(Object elem) {
174 return getProperty(elem, ARGEO_PRIMARY_EMAIL);
175 }
176 });
177
178 // Description
179 column = new TableViewerColumn(viewer, SWT.NONE);
180 column.getColumn().setText("Description");
181 column.getColumn().setWidth(200);
182 column.getColumn().addSelectionListener(getSelectionAdapter(3));
183 propertiesList.add(Property.JCR_DESCRIPTION);
184 column.setLabelProvider(new CLProvider() {
185 public String getText(Object elem) {
186 return getProperty(elem, Property.JCR_DESCRIPTION);
187 }
188 });
189
190 viewer.setComparator(new UsersViewerComparator(propertiesList));
191
192 return viewer;
193 }
194
195 private class CLProvider extends ColumnLabelProvider {
196
197 public String getToolTipText(Object element) {
198 return getText(element);
199 }
200
201 @Override
202 public Font getFont(Object elem) {
203 // self
204 String username = getProperty(elem, ARGEO_USER_ID);
205 if (username.equals(session.getUserID()))
206 return bold;
207
208 // disabled
209 try {
210 Node userProfile = (Node) elem;
211 // Node userProfile = userHome.getNode(ARGEO_PROFILE);
212 if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean())
213 return italic;
214 else
215 return null;
216 } catch (RepositoryException e) {
217 throw new ArgeoException("Cannot get font for " + username, e);
218 }
219 }
220
221 }
222
223 private SelectionAdapter getSelectionAdapter(final int index) {
224 SelectionAdapter selectionAdapter = new SelectionAdapter() {
225 @Override
226 public void widgetSelected(SelectionEvent e) {
227 UsersViewerComparator comparator = (UsersViewerComparator) viewer
228 .getComparator();
229
230 if (index == comparator.getSortColumn()) {
231 comparator.setAscending(!comparator.isAscending());
232 }
233 comparator.setSortColumn(index);
234 viewer.getTable().setSortColumn(
235 viewer.getTable().getColumn(index));
236 viewer.getTable().setSortDirection(
237 comparator.isAscending() ? SWT.UP : SWT.DOWN);
238 viewer.refresh(false);
239 }
240 };
241 return selectionAdapter;
242 }
243
244 private class UsersViewerComparator extends ViewerComparator {
245
246 private List<String> propertyList;
247 private int sortColumn = 0;
248 private boolean ascending = true;
249 // use this to enable two levels sort
250 @SuppressWarnings("unused")
251 private int lastSortColumn = 0;
252 @SuppressWarnings("unused")
253 private boolean lastAscending = true;
254
255 public UsersViewerComparator(List<String> propertyList) {
256 super();
257 this.propertyList = propertyList;
258 }
259
260 public int compare(Viewer viewer, Object e1, Object e2) {
261 String s1 = getProperty(e1, propertyList.get(sortColumn));
262 String s2 = getProperty(e2, propertyList.get(sortColumn));
263 int result = super.compare(viewer, s1, s2);
264 return ascending ? result : (-1) * result;
265 }
266
267 /**
268 * @return Returns the sortColumn.
269 */
270 public int getSortColumn() {
271 return sortColumn;
272 }
273
274 /**
275 * @param sortColumn
276 * The sortColumn to set.
277 */
278 public void setSortColumn(int sortColumn) {
279 if (this.sortColumn != sortColumn) {
280 lastSortColumn = this.sortColumn;
281 lastAscending = this.ascending;
282 this.sortColumn = sortColumn;
283 }
284 }
285
286 /**
287 * @return Returns the ascending.
288 */
289 public boolean isAscending() {
290 return ascending;
291 }
292
293 /**
294 * @param ascending
295 * The ascending to set.
296 */
297 public void setAscending(boolean ascending) {
298 this.ascending = ascending;
299 }
300 }
301
302 @Override
303 public void setFocus() {
304 viewer.getTable().setFocus();
305 }
306
307 @Override
308 public void dispose() {
309 JcrUtils.removeListenerQuietly(session, userStructureListener);
310 JcrUtils.removeListenerQuietly(session, userPropertiesListener);
311 super.dispose();
312 }
313
314 public void setSession(Session session) {
315 this.session = session;
316 }
317
318 public void refresh() {
319 // viewer.refresh();
320 refreshFilteredList();
321 }
322
323 protected String getProperty(Node userProfile, String name)
324 throws RepositoryException {
325 return userProfile.hasProperty(name) ? userProfile.getProperty(name)
326 .getString() : "";
327 }
328
329 protected String getProperty(Object element, String name) {
330 try {
331 Node userProfile = (Node) element;
332 // Node userProfile = userHome.getNode(ARGEO_PROFILE);
333 return userProfile.hasProperty(name) ? userProfile
334 .getProperty(name).getString() : "";
335 } catch (RepositoryException e) {
336 throw new ArgeoException("Cannot get property " + name, e);
337 }
338 }
339
340 private class UserStructureListener implements EventListener {
341
342 @Override
343 public void onEvent(EventIterator events) {
344 // viewer.refresh();
345 refreshFilteredList();
346 }
347 }
348
349 private class UserPropertiesListener implements EventListener {
350
351 @Override
352 public void onEvent(EventIterator events) {
353 // viewer.refresh();
354 refreshFilteredList();
355 }
356 }
357
358 private class UsersContentProvider implements IStructuredContentProvider {
359
360 public Object[] getElements(Object inputElement) {
361 return (Object[]) inputElement;
362
363 // try {
364 // Query query = session
365 // .getWorkspace()
366 // .getQueryManager()
367 // .createQuery(
368 // "select * from ["
369 // + ArgeoTypes.ARGEO_USER_PROFILE + "]",
370 // Query.JCR_SQL2);
371 // NodeIterator nit = query.execute().getNodes();
372 // List<Node> userProfiles = new ArrayList<Node>();
373 // while (nit.hasNext()) {
374 // userProfiles.add(nit.nextNode());
375 // }
376 // return userProfiles.toArray();
377 // } catch (RepositoryException e) {
378 // throw new ArgeoException("Cannot list users", e);
379 // }
380 // // return userAdminService.listUsers().toArray();
381 }
382
383 public void dispose() {
384 }
385
386 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
387 }
388
389 }
390
391 class ViewDoubleClickListener implements IDoubleClickListener {
392 public void doubleClick(DoubleClickEvent evt) {
393 if (evt.getSelection().isEmpty())
394 return;
395
396 Object obj = ((IStructuredSelection) evt.getSelection())
397 .getFirstElement();
398 if (obj instanceof Node) {
399 try {
400 String username = ((Node) obj).getProperty(ARGEO_USER_ID)
401 .getString();
402 String commandId = OpenArgeoUserEditor.COMMAND_ID;
403 String paramName = OpenArgeoUserEditor.PARAM_USERNAME;
404 CommandUtils.callCommand(commandId, paramName, username);
405 } catch (RepositoryException e) {
406 throw new ArgeoException("Cannot open user editor", e);
407 }
408 }
409 }
410 }
411
412 /* MANAGE FILTER */
413 private void createFilterPart(Composite parent) {
414 Composite header = new Composite(parent, SWT.FILL);
415 header.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
416 header.setLayout(new GridLayout(2, false));
417
418 // Text Area to filter
419 filterTxt = new Text(header, SWT.BORDER | SWT.SINGLE);
420 filterTxt.setMessage(FILTER_HELP_MSG);
421 GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
422 gd.grabExcessHorizontalSpace = true;
423 filterTxt.setLayoutData(gd);
424 filterTxt.addModifyListener(new ModifyListener() {
425 public void modifyText(ModifyEvent event) {
426 refreshFilteredList();
427 }
428 });
429
430 Button resetBtn = new Button(header, SWT.PUSH);
431 resetBtn.setImage(FILTER_RESET);
432 resetBtn.addSelectionListener(new SelectionListener() {
433 public void widgetSelected(SelectionEvent e) {
434 resetFilter();
435 }
436
437 public void widgetDefaultSelected(SelectionEvent e) {
438 }
439 });
440
441 }
442
443 private void resetFilter() {
444 filterTxt.setText("");
445 filterTxt.setMessage(FILTER_HELP_MSG);
446 }
447
448 private void refreshFilteredList() {
449 List<Node> nodes;
450 try {
451 nodes = JcrUtils.nodeIteratorToList(listFilteredElements(session,
452 filterTxt.getText()));
453 viewer.setInput(nodes.toArray());
454 } catch (RepositoryException e) {
455 throw new ArgeoException("Unable to list users", e);
456 }
457 }
458
459 /** Build repository request */
460 private NodeIterator listFilteredElements(Session session, String filter)
461 throws RepositoryException {
462 QueryManager queryManager = session.getWorkspace().getQueryManager();
463 QueryObjectModelFactory factory = queryManager.getQOMFactory();
464
465 final String bundleArtifactsSelector = "userProfiles";
466 Selector source = factory.selector(ArgeoTypes.ARGEO_USER_PROFILE,
467 bundleArtifactsSelector);
468
469 // Create a dynamic operand for each property on which we want to filter
470 DynamicOperand userIdDO = factory.propertyValue(
471 source.getSelectorName(), ARGEO_USER_ID);
472 DynamicOperand fullNameDO = factory.propertyValue(
473 source.getSelectorName(), Property.JCR_TITLE);
474 DynamicOperand mailDO = factory.propertyValue(source.getSelectorName(),
475 ARGEO_PRIMARY_EMAIL);
476
477 // Default Constraint: no source artifacts
478 Constraint defaultC = null;
479
480 // Build constraints based the textArea content
481 if (filter != null && !"".equals(filter.trim())) {
482 // Parse the String
483 String[] strs = filter.trim().split(" ");
484 for (String token : strs) {
485 token = token.replace('*', '%');
486 StaticOperand so = factory.literal(session.getValueFactory()
487 .createValue("%" + token + "%"));
488
489 Constraint currC = factory.comparison(userIdDO,
490 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
491 currC = factory.or(currC, factory.comparison(fullNameDO,
492 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
493 currC = factory.or(currC, factory.comparison(mailDO,
494 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
495
496 if (defaultC == null)
497 defaultC = currC;
498 else
499 defaultC = factory.and(defaultC, currC);
500 }
501 }
502
503 Ordering order = factory.ascending(factory.propertyValue(
504 bundleArtifactsSelector, ARGEO_USER_ID));
505 // Ordering order2 = factory.ascending(factory.propertyValue(
506 // bundleArtifactsSelector, ARGEO_PRIMARY_EMAIL));
507 // Ordering[] orderings = { order, order2 };
508 Ordering[] orderings = { order };
509
510 QueryObjectModel query = factory.createQuery(source, defaultC,
511 orderings, null);
512
513 QueryResult result = query.execute();
514 return result.getNodes();
515 }
516 }