2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.security
.ui
.admin
.views
;
18 import java
.util
.ArrayList
;
19 import java
.util
.List
;
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
;
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
;
74 /** List all users. */
75 public class UsersView
extends ViewPart
implements ArgeoNames
{
76 public final static String ID
= SecurityAdminPlugin
.PLUGIN_ID
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();
86 private Session session
;
88 private UserStructureListener userStructureListener
;
89 private UserPropertiesListener userPropertiesListener
;
95 public void createPartControl(Composite parent
) {
96 italic
= EclipseUiUtils
.getItalicFont(parent
);
97 bold
= EclipseUiUtils
.getBoldFont(parent
);
100 GridLayout layout
= new GridLayout(1, false);
101 parent
.setLayout(layout
);
102 createFilterPart(parent
);
104 viewer
= createTableViewer(parent
);
105 EclipseUiSpecificUtils
.enableToolTipSupport(viewer
);
106 viewer
.setContentProvider(new UsersContentProvider());
107 viewer
.addDoubleClickListener(new ViewDoubleClickListener());
108 getViewSite().setSelectionProvider(viewer
);
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
);
120 refreshFilteredList();
123 protected TableViewer
createTableViewer(final Composite parent
) {
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
);
131 TableViewer viewer
= new TableViewer(table
);
132 table
.setLinesVisible(true);
133 table
.setHeaderVisible(true);
135 // pass a mapping between col index and property name to the comparator.
136 List
<String
> propertiesList
= new ArrayList
<String
>();
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 + "]";
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
);
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
);
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
);
190 viewer
.setComparator(new UsersViewerComparator(propertiesList
));
195 private class CLProvider
extends ColumnLabelProvider
{
197 public String
getToolTipText(Object element
) {
198 return getText(element
);
202 public Font
getFont(Object elem
) {
204 String username
= getProperty(elem
, ARGEO_USER_ID
);
205 if (username
.equals(session
.getUserID()))
210 Node userProfile
= (Node
) elem
;
211 // Node userProfile = userHome.getNode(ARGEO_PROFILE);
212 if (!userProfile
.getProperty(ARGEO_ENABLED
).getBoolean())
216 } catch (RepositoryException e
) {
217 throw new ArgeoException("Cannot get font for " + username
, e
);
223 private SelectionAdapter
getSelectionAdapter(final int index
) {
224 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
226 public void widgetSelected(SelectionEvent e
) {
227 UsersViewerComparator comparator
= (UsersViewerComparator
) viewer
230 if (index
== comparator
.getSortColumn()) {
231 comparator
.setAscending(!comparator
.isAscending());
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);
241 return selectionAdapter
;
244 private class UsersViewerComparator
extends ViewerComparator
{
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;
255 public UsersViewerComparator(List
<String
> propertyList
) {
257 this.propertyList
= propertyList
;
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
;
268 * @return Returns the sortColumn.
270 public int getSortColumn() {
276 * The sortColumn to set.
278 public void setSortColumn(int sortColumn
) {
279 if (this.sortColumn
!= sortColumn
) {
280 lastSortColumn
= this.sortColumn
;
281 lastAscending
= this.ascending
;
282 this.sortColumn
= sortColumn
;
287 * @return Returns the ascending.
289 public boolean isAscending() {
295 * The ascending to set.
297 public void setAscending(boolean ascending
) {
298 this.ascending
= ascending
;
303 public void setFocus() {
304 viewer
.getTable().setFocus();
308 public void dispose() {
309 JcrUtils
.removeListenerQuietly(session
, userStructureListener
);
310 JcrUtils
.removeListenerQuietly(session
, userPropertiesListener
);
314 public void setSession(Session session
) {
315 this.session
= session
;
318 public void refresh() {
320 refreshFilteredList();
323 protected String
getProperty(Node userProfile
, String name
)
324 throws RepositoryException
{
325 return userProfile
.hasProperty(name
) ? userProfile
.getProperty(name
)
329 protected String
getProperty(Object element
, String name
) {
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
);
340 private class UserStructureListener
implements EventListener
{
343 public void onEvent(EventIterator events
) {
345 refreshFilteredList();
349 private class UserPropertiesListener
implements EventListener
{
352 public void onEvent(EventIterator events
) {
354 refreshFilteredList();
358 private class UsersContentProvider
implements IStructuredContentProvider
{
360 public Object
[] getElements(Object inputElement
) {
361 return (Object
[]) inputElement
;
364 // Query query = session
366 // .getQueryManager()
369 // + ArgeoTypes.ARGEO_USER_PROFILE + "]",
371 // NodeIterator nit = query.execute().getNodes();
372 // List<Node> userProfiles = new ArrayList<Node>();
373 // while (nit.hasNext()) {
374 // userProfiles.add(nit.nextNode());
376 // return userProfiles.toArray();
377 // } catch (RepositoryException e) {
378 // throw new ArgeoException("Cannot list users", e);
380 // // return userAdminService.listUsers().toArray();
383 public void dispose() {
386 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
391 class ViewDoubleClickListener
implements IDoubleClickListener
{
392 public void doubleClick(DoubleClickEvent evt
) {
393 if (evt
.getSelection().isEmpty())
396 Object obj
= ((IStructuredSelection
) evt
.getSelection())
398 if (obj
instanceof Node
) {
400 String username
= ((Node
) obj
).getProperty(ARGEO_USER_ID
)
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
);
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));
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();
430 Button resetBtn
= new Button(header
, SWT
.PUSH
);
431 resetBtn
.setImage(FILTER_RESET
);
432 resetBtn
.addSelectionListener(new SelectionListener() {
433 public void widgetSelected(SelectionEvent e
) {
437 public void widgetDefaultSelected(SelectionEvent e
) {
443 private void resetFilter() {
444 filterTxt
.setText("");
445 filterTxt
.setMessage(FILTER_HELP_MSG
);
448 private void refreshFilteredList() {
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
);
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();
465 final String bundleArtifactsSelector
= "userProfiles";
466 Selector source
= factory
.selector(ArgeoTypes
.ARGEO_USER_PROFILE
,
467 bundleArtifactsSelector
);
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
);
477 // Default Constraint: no source artifacts
478 Constraint defaultC
= null;
480 // Build constraints based the textArea content
481 if (filter
!= null && !"".equals(filter
.trim())) {
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
+ "%"));
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
));
496 if (defaultC
== null)
499 defaultC
= factory
.and(defaultC
, currC
);
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
};
510 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
513 QueryResult result
= query
.execute();
514 return result
.getNodes();