|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.panels.usermgr.client.swing; |
|
27 |
|
28 import javax.swing.*; |
|
29 import javax.swing.event.*; |
|
30 import javax.swing.tree.*; |
|
31 import javax.swing.border.*; |
|
32 |
|
33 import java.awt.*; |
|
34 import java.awt.event.*; |
|
35 import java.util.*; |
|
36 |
|
37 import com.oracle.solaris.vp.util.misc.finder.Finder; |
|
38 |
|
39 /** |
|
40 * SMC code adapted for Visual Panels |
|
41 * |
|
42 * Rights Profiles Panel for Rights Settings |
|
43 */ |
|
44 public class AuthRightsPanel extends JPanel { |
|
45 |
|
46 |
|
47 public static Arranger profPanel; |
|
48 private static DblTreeNode srcRoot; |
|
49 private static DblTreeNode dstRoot; |
|
50 private DefaultTreeModel srcModel, dstModel; |
|
51 |
|
52 private DblTreeNode [] profNodes; |
|
53 private ProfTreeNode [] profTreeNodes; |
|
54 |
|
55 private ProfTreeNode currProfTreeNode; |
|
56 private DblTreeNode currDblTreeNode; |
|
57 |
|
58 private String targetRightName; |
|
59 private String targetRight; |
|
60 private JPanel securityPanel; |
|
61 |
|
62 private UserManagedObject userObj = null; |
|
63 private UserMgrPanelDescriptor panelDesc = null; |
|
64 |
|
65 private Vector vAllRightObjs = null; |
|
66 |
|
67 private boolean isProfListOK = true; |
|
68 |
|
69 /** |
|
70 * Constructs a panel to contain supplementary rights properties for |
|
71 * the right object. |
|
72 */ |
|
73 public AuthRightsPanel(UserMgrPanelDescriptor panelDesc, |
|
74 UserManagedObject userObj) { |
|
75 |
|
76 super(); |
|
77 this.panelDesc = panelDesc; |
|
78 this.userObj = userObj; |
|
79 |
|
80 createGui(); |
|
81 loadProfiles(); |
|
82 } // constructor |
|
83 |
|
84 |
|
85 /** |
|
86 * Method for creating GUI |
|
87 */ |
|
88 private void createGui() { |
|
89 |
|
90 // Set the panel layout |
|
91 GridBagConstraints gbc = new GridBagConstraints(); |
|
92 this.setLayout(new GridBagLayout()); |
|
93 |
|
94 // Excluded and Included rights panel |
|
95 securityPanel = null; |
|
96 |
|
97 profPanel = new Arranger("usermgr.advanced.auth_rights.available", |
|
98 "usermgr.advanced.auth_rights.granted"); |
|
99 |
|
100 Dimension dimension = new Dimension(200, 300); |
|
101 profPanel.srcTree.setCellRenderer(new ProfileRenderer(this)); |
|
102 profPanel.srcTree.setVisibleRowCount(10); |
|
103 profPanel.srcTree.setSize(dimension); |
|
104 |
|
105 profPanel.dstTree.setCellRenderer(new ProfileRenderer(this)); |
|
106 profPanel.dstTree.setVisibleRowCount(10); |
|
107 profPanel.dstTree.setSize(dimension); |
|
108 |
|
109 Constraints.constrain(this, profPanel, |
|
110 0, 0, 1, 1, |
|
111 gbc.BOTH, gbc.CENTER, |
|
112 1.0, 1.0, 10, 10, 10, 10); |
|
113 |
|
114 } // end createGui |
|
115 |
|
116 |
|
117 /** |
|
118 * Load the Source and Destination trees for rights excluded and |
|
119 * included lists. |
|
120 */ |
|
121 private void loadProfiles() { |
|
122 |
|
123 // Reset the data models. So old data is discarded |
|
124 profPanel.resetModels(); |
|
125 |
|
126 |
|
127 // Initialize the excluded rights list with all profiles |
|
128 // except for the current one, since a profile can not be |
|
129 // assigned to itself. Note that all profiles are created |
|
130 // as top-level profiles. |
|
131 |
|
132 vAllRightObjs = getAvailableProfs(); |
|
133 |
|
134 srcModel = (DefaultTreeModel) profPanel.srcTree.getModel(); |
|
135 srcRoot = (DblTreeNode) srcModel.getRoot(); |
|
136 |
|
137 dstModel = (DefaultTreeModel) profPanel.dstTree.getModel(); |
|
138 dstRoot = (DblTreeNode) dstModel.getRoot(); |
|
139 |
|
140 profNodes = new DblTreeNode[vAllRightObjs.size()]; |
|
141 profTreeNodes = new ProfTreeNode[vAllRightObjs.size()]; |
|
142 |
|
143 int n = 0; |
|
144 Enumeration e = vAllRightObjs.elements(); |
|
145 |
|
146 // Build an array of tree nodes that can be used for sorting. |
|
147 |
|
148 while (e.hasMoreElements()) { |
|
149 String rightObj = (String)e.nextElement(); |
|
150 String rightName = rightObj; |
|
151 |
|
152 profTreeNodes[n] = new ProfTreeNode(rightObj); |
|
153 |
|
154 n++; |
|
155 } |
|
156 |
|
157 // Sort the list of ProfTreeNode objects. |
|
158 |
|
159 if (profTreeNodes.length > 1) { |
|
160 NodeCompare comp = new NodeCompare(); |
|
161 Sort.sort(profTreeNodes, comp); |
|
162 } |
|
163 |
|
164 // With the sorted tree nodes, now we build the src tree. |
|
165 for (int i = 0; i < profTreeNodes.length; i++) { |
|
166 profNodes[i] = new DblTreeNode((Object)profTreeNodes[i]); |
|
167 |
|
168 srcModel.insertNodeInto(profNodes[i], srcRoot, i); |
|
169 TreePath nodepath = new TreePath(profNodes[i].getPath()); |
|
170 // Make initial display of excluded list |
|
171 profPanel.srcTree.scrollPathToVisible(nodepath); |
|
172 } |
|
173 |
|
174 |
|
175 // Set TreeModel listeners |
|
176 srcModel.addTreeModelListener(new TreeModelListener() { |
|
177 |
|
178 public void treeNodesInserted(TreeModelEvent e) { |
|
179 enableProfileChoices(e); |
|
180 } |
|
181 |
|
182 public void treeNodesRemoved(TreeModelEvent e) { |
|
183 disableProfileChoices(e); |
|
184 } |
|
185 |
|
186 public void treeNodesChanged(TreeModelEvent e) {} |
|
187 |
|
188 public void treeStructureChanged(TreeModelEvent e) {} |
|
189 |
|
190 }); |
|
191 |
|
192 dstModel.addTreeModelListener(new TreeModelListener() { |
|
193 |
|
194 public void treeNodesInserted(TreeModelEvent e) { |
|
195 updateDstTree(e); |
|
196 } |
|
197 |
|
198 public void treeNodesRemoved(TreeModelEvent e) { |
|
199 updateDstTree(e); |
|
200 } |
|
201 |
|
202 public void treeNodesChanged(TreeModelEvent e) {} |
|
203 |
|
204 public void treeStructureChanged(TreeModelEvent e) {} |
|
205 |
|
206 }); |
|
207 |
|
208 // Build subprofiles recursively |
|
209 for (int i = 0; i < profNodes.length; i++) { |
|
210 rebuildSubProfiles(profNodes[i], profNodes[i]); |
|
211 } |
|
212 |
|
213 String [] subProfList = null; |
|
214 |
|
215 // Get the list of profiles that are assigned to current user/role |
|
216 // (in user_attr entry). |
|
217 String rights = userObj.getAuthRights(); |
|
218 if (rights != null) { |
|
219 subProfList = userObj.getAuthRights().split(","); |
|
220 } |
|
221 |
|
222 profPanel.setInitSelection(); |
|
223 if (rights == null || subProfList == null) { |
|
224 return; |
|
225 } |
|
226 |
|
227 // Move subprofiles of current profile from excluded list |
|
228 // to included list. |
|
229 // Note that a dimmed profile will stay dimmed after the move. |
|
230 // Therefore, a user can not "unassign" a dimmed profile on the |
|
231 // included list. |
|
232 |
|
233 |
|
234 for (int j = 0; j < subProfList.length; j++) { |
|
235 boolean foundSubProf = false; |
|
236 |
|
237 int count = 0; |
|
238 for (int i = 0; i < profNodes.length; i++) { |
|
239 String profString = profNodes[i].toString(); |
|
240 |
|
241 if (profString.equals(subProfList[j])) { |
|
242 foundSubProf = true; |
|
243 count = i; |
|
244 break; |
|
245 } |
|
246 |
|
247 } |
|
248 |
|
249 if (foundSubProf) { |
|
250 profPanel.initLeaf(profPanel.srcTree, |
|
251 profPanel.dstTree, profNodes[count]); |
|
252 } |
|
253 } |
|
254 |
|
255 profPanel.setInitSelection(); |
|
256 |
|
257 } // end loadProfiles |
|
258 |
|
259 |
|
260 private void updateDstTree(TreeModelEvent e) { |
|
261 |
|
262 Vector<DblTreeNode> inclProfsVec = new Vector<DblTreeNode>(); |
|
263 Enumeration inclProfsEnum = dstRoot.breadthFirstEnumeration(); |
|
264 |
|
265 while (inclProfsEnum.hasMoreElements()) { |
|
266 DblTreeNode node = (DblTreeNode)inclProfsEnum.nextElement(); |
|
267 inclProfsVec.addElement(node); |
|
268 node.setConflict(false); |
|
269 } |
|
270 |
|
271 // Maintain included names as array as optimization |
|
272 |
|
273 DblTreeNode [] inclProfs = new DblTreeNode[inclProfsVec.size()]; |
|
274 inclProfsVec.copyInto(inclProfs); |
|
275 |
|
276 if (inclProfs.length < 2) |
|
277 return; |
|
278 |
|
279 for (int i = 0; i < inclProfs.length; i++) { |
|
280 String testString = inclProfs[i].toString(); |
|
281 |
|
282 for (int j = i + 1; j < inclProfs.length; j++) { |
|
283 if (testString.equals(inclProfs[j].toString())) { |
|
284 inclProfs[j].setConflict(true); |
|
285 inclProfs[i].setConflict(true); |
|
286 TreeNode [] nodes = inclProfs[j].getPath(); |
|
287 DblTreeNode parentProf = (DblTreeNode)nodes[1]; |
|
288 parentProf.setConflict(true); |
|
289 } |
|
290 } |
|
291 } |
|
292 |
|
293 } // end updateDstTree |
|
294 |
|
295 |
|
296 private void enableProfileChoices(TreeModelEvent e) { |
|
297 |
|
298 // Get names of currently included profiles |
|
299 if (e.getPath().length > 1) |
|
300 return; |
|
301 |
|
302 Vector<String> inclProfsVec = new Vector<String>(); |
|
303 Enumeration inclProfs = dstRoot.depthFirstEnumeration(); |
|
304 |
|
305 while (inclProfs.hasMoreElements()) { |
|
306 inclProfsVec.addElement(inclProfs.nextElement().toString()); |
|
307 } |
|
308 |
|
309 // Maintain included names as array as optimization |
|
310 |
|
311 String [] inclProfNames = new String[inclProfsVec.size()]; |
|
312 inclProfsVec.copyInto(inclProfNames); |
|
313 |
|
314 // Look for excluded list items needing updating |
|
315 |
|
316 Enumeration topProfs = srcRoot.children(); |
|
317 while (topProfs.hasMoreElements()) { |
|
318 DblTreeNode nextTop = (DblTreeNode)topProfs.nextElement(); |
|
319 boolean matchFound = false; |
|
320 Enumeration exclProfs = nextTop.depthFirstEnumeration(); |
|
321 |
|
322 while (exclProfs.hasMoreElements()) { |
|
323 String testString = exclProfs.nextElement().toString(); |
|
324 for (int i = 0; i < inclProfNames.length; i++) { |
|
325 if (testString.equals(inclProfNames[i])) { |
|
326 matchFound = true; |
|
327 break; |
|
328 } |
|
329 } |
|
330 if (matchFound) |
|
331 break; |
|
332 } |
|
333 |
|
334 // A Profile hierarchy needs to be enabled |
|
335 |
|
336 if (!matchFound) { |
|
337 exclProfs = nextTop.depthFirstEnumeration(); |
|
338 while (exclProfs.hasMoreElements()) { |
|
339 DblTreeNode onNode = |
|
340 (DblTreeNode) exclProfs.nextElement(); |
|
341 onNode.setConflict(false); |
|
342 } |
|
343 nextTop.setConflict(false); |
|
344 } |
|
345 } |
|
346 |
|
347 } // end enableProfileChoices |
|
348 |
|
349 |
|
350 private void disableProfileChoices(TreeModelEvent e) { |
|
351 |
|
352 if (e.getPath().length > 1) |
|
353 return; |
|
354 |
|
355 Object[] children = e.getChildren(); |
|
356 DblTreeNode node = (DblTreeNode)children[0]; |
|
357 Enumeration kids = node.breadthFirstEnumeration(); |
|
358 while (kids.hasMoreElements()) { |
|
359 disableRecursively((DblTreeNode)kids.nextElement()); |
|
360 } |
|
361 |
|
362 } // end disableProfileChoices |
|
363 |
|
364 |
|
365 private void disableRecursively(DblTreeNode node) { |
|
366 |
|
367 String testString = node.toString(); |
|
368 Enumeration exclProfs = srcRoot.breadthFirstEnumeration(); |
|
369 while (exclProfs.hasMoreElements()) { |
|
370 DblTreeNode exclNode = (DblTreeNode)exclProfs.nextElement(); |
|
371 if (testString.equals(exclNode.toString())) { |
|
372 TreeNode [] nodes = exclNode.getPath(); |
|
373 |
|
374 DblTreeNode parentProf = (DblTreeNode)nodes[1]; |
|
375 if (!parentProf.isConflict()) { |
|
376 parentProf.setConflict(true); |
|
377 exclNode.setConflict(true); |
|
378 } |
|
379 } |
|
380 } |
|
381 |
|
382 } // end disableRecursively |
|
383 |
|
384 |
|
385 private void rebuildSubProfiles(DblTreeNode profNode, DblTreeNode topNode) { |
|
386 |
|
387 // First unlink the old children |
|
388 int childCount = profNode.getChildCount(); |
|
389 for (int i = 0; i < childCount; i++) { |
|
390 DblTreeNode child = (DblTreeNode) srcModel.getChild(profNode, 0); |
|
391 srcModel.removeNodeFromParent(child); |
|
392 } |
|
393 |
|
394 // Then recursively construct new nodes for all the children |
|
395 DblTreeNode childNode; |
|
396 int i = 0; |
|
397 Enumeration topList = topNode.breadthFirstEnumeration(); |
|
398 |
|
399 // Find sub-profile list in RightObj of cached tree node |
|
400 ProfTreeNode pTreeNode = (ProfTreeNode)profNode.getUserObject(); |
|
401 String rObj = pTreeNode.getRightObj(); |
|
402 // ProfAttrObj targetProfAttr = rObj.getProfAttr(); |
|
403 |
|
404 String [] profList = null; // targetProfAttr.getProfNames(); |
|
405 |
|
406 if (profList == null) |
|
407 return; |
|
408 |
|
409 for (int k = 0; k < profList.length; k++) { |
|
410 String name = profList[k]; |
|
411 |
|
412 // Prevent infinite recursive loops |
|
413 boolean cyclic = false; |
|
414 while (topList.hasMoreElements()) { |
|
415 if (name.equals(topList.nextElement().toString())) { |
|
416 cyclic = true; |
|
417 // Mark the parent as cyclic |
|
418 topNode.setCyclic(true); |
|
419 Enumeration dupNodes = topNode.breadthFirstEnumeration(); |
|
420 while (dupNodes.hasMoreElements()) { |
|
421 childNode = (DblTreeNode)dupNodes.nextElement(); |
|
422 if (name.equals(childNode.toString())) { |
|
423 childNode.setCyclic(true); |
|
424 } |
|
425 } |
|
426 break; |
|
427 } |
|
428 } |
|
429 |
|
430 for (int j = 0; j < profTreeNodes.length; j++) { |
|
431 if (name.equals(profTreeNodes[j].toString())) { |
|
432 childNode = new DblTreeNode((Object)profTreeNodes[j]); |
|
433 |
|
434 srcModel.insertNodeInto(childNode, profNode, i++); |
|
435 childNode.setEnabled(false); |
|
436 if (cyclic) |
|
437 childNode.setCyclic(true); |
|
438 else |
|
439 rebuildSubProfiles(childNode, topNode); |
|
440 } |
|
441 } |
|
442 } |
|
443 |
|
444 } // end rebuildSubProfiles |
|
445 |
|
446 |
|
447 public String updateRightSubProps(String rightObj) { |
|
448 |
|
449 if (isProfListOK) { |
|
450 Vector<String> vAssignedProfs = new Vector<String>(); |
|
451 |
|
452 // Get the first generation children that are assigned to |
|
453 // current profile. |
|
454 DblTreeNode root = (DblTreeNode)dstModel.getRoot(); |
|
455 Enumeration kids; |
|
456 kids = root.children(); |
|
457 |
|
458 while (kids.hasMoreElements()) { |
|
459 DblTreeNode childNode; |
|
460 childNode = (DblTreeNode)kids.nextElement(); |
|
461 vAssignedProfs.addElement(childNode.toString()); |
|
462 } |
|
463 |
|
464 // ProfAttrObj profAttr = rightObj.getProfAttr(); |
|
465 // profAttr.setProfNamesVector(vAssignedProfs); |
|
466 } |
|
467 return (rightObj); |
|
468 |
|
469 } // end updateRightSubProps |
|
470 |
|
471 public Vector<String> getAssignedProfs() { |
|
472 Vector<String> vAssignedProfs = new Vector<String>(); |
|
473 |
|
474 if (!isProfListOK) { |
|
475 return vAssignedProfs; |
|
476 } |
|
477 |
|
478 // Get the first generation children that are assigned to |
|
479 // current profile. |
|
480 DblTreeNode root = (DblTreeNode)dstModel.getRoot(); |
|
481 Enumeration kids; |
|
482 kids = root.children(); |
|
483 while (kids.hasMoreElements()) { |
|
484 DblTreeNode childNode; |
|
485 childNode = (DblTreeNode)kids.nextElement(); |
|
486 vAssignedProfs.addElement(childNode.toString()); |
|
487 } |
|
488 |
|
489 return vAssignedProfs; |
|
490 } |
|
491 |
|
492 private Vector<String> getAvailableProfs() { |
|
493 Vector<String> rights = new Vector<String>(); |
|
494 for (String s : panelDesc.getProfiles()) { |
|
495 rights.add(s); |
|
496 |
|
497 } |
|
498 return (rights); |
|
499 } |
|
500 |
|
501 public void setUser(UserManagedObject userObj) { |
|
502 this.userObj = userObj; |
|
503 loadProfiles(); |
|
504 } |
|
505 |
|
506 public UserManagedObject updateUser() { |
|
507 Vector<String> vProfs = getAssignedProfs(); |
|
508 String profStr; |
|
509 |
|
510 if (vProfs.size() > 0) { |
|
511 profStr = vProfs.elementAt(0); |
|
512 } else { |
|
513 profStr = ""; |
|
514 } |
|
515 |
|
516 for (int i = 1; i < vProfs.size(); i++) { |
|
517 profStr = profStr.concat(","); |
|
518 profStr = profStr.concat(vProfs.elementAt(i)); |
|
519 } |
|
520 |
|
521 userObj.getAuthRightsProperty().setValue(profStr); |
|
522 |
|
523 return (userObj); |
|
524 } |
|
525 |
|
526 |
|
527 |
|
528 class ProfileRenderer extends DefaultTreeCellRenderer { |
|
529 |
|
530 private boolean selected; |
|
531 Icon warningIcon; |
|
532 AuthRightsPanel rightsPanel; |
|
533 |
|
534 public ProfileRenderer(AuthRightsPanel rightsPanel) { |
|
535 |
|
536 this.rightsPanel = rightsPanel; |
|
537 setClosedIcon(null); |
|
538 setOpenIcon(null); |
|
539 setLeafIcon(null); |
|
540 warningIcon = Finder.getIcon("images/warning.gif"); |
|
541 |
|
542 } |
|
543 |
|
544 |
|
545 public Component getTreeCellRendererComponent( |
|
546 JTree tree, |
|
547 Object value, |
|
548 boolean selected, |
|
549 boolean expanded, |
|
550 boolean leaf, |
|
551 int row, |
|
552 boolean hasFocus) { |
|
553 |
|
554 FocusEvent e = null; |
|
555 |
|
556 this.selected = selected; |
|
557 |
|
558 DefaultTreeCellRenderer cr = |
|
559 (DefaultTreeCellRenderer)tree.getCellRenderer(); |
|
560 cr.setLeafIcon(null); |
|
561 DblTreeNode node = (DblTreeNode)value; |
|
562 |
|
563 if (node.getParent() == null) { |
|
564 // maybe the same as row == 0 |
|
565 setText(node.toString()); |
|
566 |
|
567 } else if (node.getUserObject() instanceof ProfTreeNode) { |
|
568 ProfTreeNode profsdef = (ProfTreeNode)node.getUserObject(); |
|
569 setText(profsdef.toString()); |
|
570 // setIcon(actionIcon); |
|
571 |
|
572 if (node.isConflict()) |
|
573 if (tree == rightsPanel.profPanel.dstTree) |
|
574 cr.setLeafIcon(warningIcon); |
|
575 } |
|
576 |
|
577 super.getTreeCellRendererComponent(tree, value, selected, expanded, |
|
578 leaf, row, hasFocus); |
|
579 |
|
580 return this; |
|
581 |
|
582 } // end getTreeCellRendererComponent |
|
583 |
|
584 } |
|
585 |
|
586 class ProfTreeNode { |
|
587 |
|
588 String name; |
|
589 String rightObj = null; |
|
590 |
|
591 public ProfTreeNode(String rightObj) { |
|
592 this.rightObj = rightObj; |
|
593 this.name = rightObj; |
|
594 } |
|
595 |
|
596 public String getRightObj() { |
|
597 return rightObj; |
|
598 } |
|
599 |
|
600 public String toString() { |
|
601 return name; |
|
602 } |
|
603 |
|
604 } |
|
605 |
|
606 class NodeCompare implements Compare { |
|
607 |
|
608 /** |
|
609 * The compare method compares two ProfTreeNode objects by comparing |
|
610 * their profile names. The parameters are specified as Object class |
|
611 * objects for QuickSort. |
|
612 * |
|
613 * @param a The first Node. |
|
614 * @param b The second Node. |
|
615 * |
|
616 */ |
|
617 public final int doCompare(Object a, Object b) { |
|
618 |
|
619 ProfTreeNode e1, e2; |
|
620 String e1Name, e2Name; |
|
621 |
|
622 e1 = (ProfTreeNode)a; |
|
623 e2 = (ProfTreeNode)b; |
|
624 e1Name = e1.toString(); |
|
625 e2Name = e2.toString(); |
|
626 return (e1Name.compareTo(e2Name)); |
|
627 |
|
628 } |
|
629 |
|
630 } |
|
631 } |