components/visual-panels/usermgr/src/java/vpanels/app/usermgr/com/oracle/solaris/vp/panels/usermgr/client/swing/AuthRightsPanel.java
author devjani.ray@oracle.com <devjani.ray@oracle.com>
Wed, 30 Oct 2013 16:53:48 -0400
branchs11-update
changeset 2805 4888f6212f94
permissions -rw-r--r--
17510631 Backport 16984138 to 11.2 - vp components must change to match RAD2 enhancements 17548766 Backport 16808665 to 11.2 - User Manager Panel can assign profiles, but not auth

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
 */

package com.oracle.solaris.vp.panels.usermgr.client.swing;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.border.*;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import com.oracle.solaris.vp.util.misc.finder.Finder;

/**
 * SMC code adapted for Visual Panels
 *
 * Rights Profiles Panel for Rights Settings
 */
public class AuthRightsPanel extends JPanel {


    public static Arranger profPanel;
    private static DblTreeNode srcRoot;
    private static DblTreeNode dstRoot;
    private DefaultTreeModel srcModel, dstModel;

    private DblTreeNode [] profNodes;
    private ProfTreeNode [] profTreeNodes;

    private ProfTreeNode currProfTreeNode;
    private DblTreeNode currDblTreeNode;

    private String targetRightName;
    private String targetRight;
    private JPanel securityPanel;

    private UserManagedObject userObj = null;
    private UserMgrPanelDescriptor panelDesc = null;

    private Vector vAllRightObjs = null;

    private boolean isProfListOK = true;

    /**
     * Constructs a panel to contain supplementary rights properties for
     * the right object.
     */
    public AuthRightsPanel(UserMgrPanelDescriptor panelDesc,
        UserManagedObject userObj) {

	super();
	this.panelDesc = panelDesc;
	this.userObj = userObj;

	createGui();
	loadProfiles();
    } // constructor


    /**
     * Method for creating GUI
     */
    private void createGui() {

	// Set the panel layout
	GridBagConstraints gbc = new GridBagConstraints();
	this.setLayout(new GridBagLayout());

	// Excluded and Included rights panel
   	securityPanel = null;

	profPanel = new Arranger("usermgr.advanced.auth_rights.available",
		"usermgr.advanced.auth_rights.granted");

	Dimension dimension = new Dimension(200, 300);
	profPanel.srcTree.setCellRenderer(new ProfileRenderer(this));
	profPanel.srcTree.setVisibleRowCount(10);
	profPanel.srcTree.setSize(dimension);

	profPanel.dstTree.setCellRenderer(new ProfileRenderer(this));
	profPanel.dstTree.setVisibleRowCount(10);
	profPanel.dstTree.setSize(dimension);

	Constraints.constrain(this, profPanel,
		0, 0, 1, 1,
		gbc.BOTH, gbc.CENTER,
		1.0, 1.0, 10, 10, 10, 10);

    } // end createGui


    /**
     * Load the Source and Destination trees for rights excluded and
     * included lists.
     */
    private void loadProfiles() {

	// Reset the data models. So old data is discarded
	profPanel.resetModels();


	// Initialize the excluded rights list with all profiles
	// except for the current one, since a profile can not be
	// assigned to itself. Note that all profiles are created
	// as top-level profiles.

	vAllRightObjs = getAvailableProfs();

	srcModel = (DefaultTreeModel) profPanel.srcTree.getModel();
	srcRoot = (DblTreeNode) srcModel.getRoot();

	dstModel = (DefaultTreeModel) profPanel.dstTree.getModel();
	dstRoot = (DblTreeNode) dstModel.getRoot();

	profNodes = new DblTreeNode[vAllRightObjs.size()];
	profTreeNodes = new ProfTreeNode[vAllRightObjs.size()];

	int n = 0;
	Enumeration e = vAllRightObjs.elements();

	// Build an array of tree nodes that can be used for sorting.

	while (e.hasMoreElements()) {
	    String rightObj = (String)e.nextElement();
	    String rightName = rightObj;

	    profTreeNodes[n] = new ProfTreeNode(rightObj);

	    n++;
	}

	// Sort the list of ProfTreeNode objects.

	if (profTreeNodes.length > 1) {
	    NodeCompare comp = new NodeCompare();
	    Sort.sort(profTreeNodes, comp);
	}

	// With the sorted tree nodes, now we build the src tree.
	for (int i = 0; i < profTreeNodes.length; i++) {
	    profNodes[i] = new DblTreeNode((Object)profTreeNodes[i]);

	    srcModel.insertNodeInto(profNodes[i], srcRoot, i);
	    TreePath nodepath = new TreePath(profNodes[i].getPath());
	    // Make initial display of excluded list
	    profPanel.srcTree.scrollPathToVisible(nodepath);
	}


	// Set TreeModel listeners
	srcModel.addTreeModelListener(new TreeModelListener() {

	    public void treeNodesInserted(TreeModelEvent e) {
		enableProfileChoices(e);
	    }

	    public void treeNodesRemoved(TreeModelEvent e) {
		disableProfileChoices(e);
	    }

	    public void treeNodesChanged(TreeModelEvent e) {}

	    public void treeStructureChanged(TreeModelEvent e) {}

	});

	dstModel.addTreeModelListener(new TreeModelListener() {

	    public void treeNodesInserted(TreeModelEvent e) {
		updateDstTree(e);
	    }

	    public void treeNodesRemoved(TreeModelEvent e) {
		updateDstTree(e);
	    }

	    public void treeNodesChanged(TreeModelEvent e) {}

	    public void treeStructureChanged(TreeModelEvent e) {}

	});

	// Build subprofiles recursively
	for (int i = 0; i < profNodes.length; i++) {
	    rebuildSubProfiles(profNodes[i], profNodes[i]);
	}

	String [] subProfList = null;

	// Get the list of profiles that are assigned to current user/role
	// (in user_attr entry).
	String rights = userObj.getAuthRights();
	if (rights != null) {
	    subProfList = userObj.getAuthRights().split(",");
	}

	profPanel.setInitSelection();
	if (rights == null || subProfList == null) {
	    return;
	}

	// Move subprofiles of current profile from excluded list
	// to included list.
	// Note that a dimmed profile will stay dimmed after the move.
	// Therefore, a user can not "unassign" a dimmed profile on the
	// included list.


	for (int j = 0; j < subProfList.length; j++) {
	    boolean foundSubProf = false;

	    int count = 0;
	    for (int i = 0; i < profNodes.length; i++) {
		String profString = profNodes[i].toString();

		if (profString.equals(subProfList[j])) {
		    foundSubProf = true;
		    count = i;
		    break;
		}

	    }

	    if (foundSubProf) {
		profPanel.initLeaf(profPanel.srcTree,
		    profPanel.dstTree, profNodes[count]);
	    }
	}

	profPanel.setInitSelection();

    } // end loadProfiles


    private void updateDstTree(TreeModelEvent e) {

	Vector<DblTreeNode> inclProfsVec = new Vector<DblTreeNode>();
	Enumeration inclProfsEnum = dstRoot.breadthFirstEnumeration();

	while (inclProfsEnum.hasMoreElements()) {
	    DblTreeNode node = (DblTreeNode)inclProfsEnum.nextElement();
	    inclProfsVec.addElement(node);
	    node.setConflict(false);
	}

	// Maintain included names as array as optimization

	DblTreeNode [] inclProfs = new DblTreeNode[inclProfsVec.size()];
	inclProfsVec.copyInto(inclProfs);

	if (inclProfs.length < 2)
	    return;

	for (int i = 0; i < inclProfs.length; i++) {
	    String testString = inclProfs[i].toString();

	    for (int j = i + 1; j < inclProfs.length; j++) {
		if (testString.equals(inclProfs[j].toString())) {
		    inclProfs[j].setConflict(true);
		    inclProfs[i].setConflict(true);
		    TreeNode [] nodes = inclProfs[j].getPath();
		    DblTreeNode parentProf = (DblTreeNode)nodes[1];
		    parentProf.setConflict(true);
		}
	    }
	}

    } // end updateDstTree


    private void enableProfileChoices(TreeModelEvent e) {

	// Get names of currently included profiles
	if (e.getPath().length > 1)
	    return;

	Vector<String> inclProfsVec = new Vector<String>();
	Enumeration inclProfs = dstRoot.depthFirstEnumeration();

	while (inclProfs.hasMoreElements()) {
	    inclProfsVec.addElement(inclProfs.nextElement().toString());
	}

	// Maintain included names as array as optimization

	String [] inclProfNames = new String[inclProfsVec.size()];
	inclProfsVec.copyInto(inclProfNames);

	// Look for excluded list items needing updating

	Enumeration topProfs = srcRoot.children();
	while (topProfs.hasMoreElements()) {
	    DblTreeNode nextTop = (DblTreeNode)topProfs.nextElement();
	    boolean matchFound = false;
	    Enumeration exclProfs = nextTop.depthFirstEnumeration();

	    while (exclProfs.hasMoreElements()) {
		String testString = exclProfs.nextElement().toString();
		for (int i = 0; i < inclProfNames.length; i++) {
		    if (testString.equals(inclProfNames[i])) {
			matchFound = true;
			break;
		    }
		}
		if (matchFound)
		    break;
	    }

	    // A Profile hierarchy needs to be enabled

	    if (!matchFound) {
		exclProfs = nextTop.depthFirstEnumeration();
		while (exclProfs.hasMoreElements()) {
		    DblTreeNode onNode =
			(DblTreeNode) exclProfs.nextElement();
		    onNode.setConflict(false);
		}
		nextTop.setConflict(false);
	    }
	}

    } // end enableProfileChoices


    private void disableProfileChoices(TreeModelEvent e) {

	if (e.getPath().length > 1)
	    return;

	Object[] children = e.getChildren();
	DblTreeNode node = (DblTreeNode)children[0];
	Enumeration kids = node.breadthFirstEnumeration();
	while (kids.hasMoreElements()) {
	    disableRecursively((DblTreeNode)kids.nextElement());
	}

    } // end disableProfileChoices


    private void disableRecursively(DblTreeNode node) {

	String testString = node.toString();
	Enumeration exclProfs = srcRoot.breadthFirstEnumeration();
	while (exclProfs.hasMoreElements()) {
	    DblTreeNode exclNode = (DblTreeNode)exclProfs.nextElement();
	    if (testString.equals(exclNode.toString())) {
		TreeNode [] nodes = exclNode.getPath();

		DblTreeNode parentProf = (DblTreeNode)nodes[1];
		if (!parentProf.isConflict()) {
		    parentProf.setConflict(true);
		    exclNode.setConflict(true);
    		}
	    }
	}

    } // end disableRecursively


    private void rebuildSubProfiles(DblTreeNode profNode, DblTreeNode topNode) {

	// First unlink the old children
	int childCount = profNode.getChildCount();
	for (int i = 0; i < childCount; i++) {
	    DblTreeNode child = (DblTreeNode) srcModel.getChild(profNode, 0);
	    srcModel.removeNodeFromParent(child);
	}

	// Then recursively construct new nodes for all the children
	DblTreeNode childNode;
	int i = 0;
	Enumeration topList = topNode.breadthFirstEnumeration();

	// Find sub-profile list in RightObj of cached tree node
	ProfTreeNode pTreeNode = (ProfTreeNode)profNode.getUserObject();
	String rObj = pTreeNode.getRightObj();
	// ProfAttrObj targetProfAttr = rObj.getProfAttr();

	String [] profList = null; // targetProfAttr.getProfNames();

	if (profList == null)
	    return;

	for (int k = 0; k < profList.length; k++) {
	    String name = profList[k];

	    // Prevent infinite recursive loops
	    boolean cyclic = false;
	    while (topList.hasMoreElements()) {
		if (name.equals(topList.nextElement().toString())) {
		    cyclic = true;
		    // Mark the parent as cyclic
		    topNode.setCyclic(true);
		    Enumeration dupNodes = topNode.breadthFirstEnumeration();
		    while (dupNodes.hasMoreElements()) {
			childNode = (DblTreeNode)dupNodes.nextElement();
			if (name.equals(childNode.toString())) {
			    childNode.setCyclic(true);
			}
		    }
		    break;
		}
	    }

	    for (int j = 0; j < profTreeNodes.length; j++) {
		if (name.equals(profTreeNodes[j].toString())) {
		    childNode = new DblTreeNode((Object)profTreeNodes[j]);

		    srcModel.insertNodeInto(childNode, profNode, i++);
		    childNode.setEnabled(false);
		    if (cyclic)
			childNode.setCyclic(true);
		    else
			rebuildSubProfiles(childNode, topNode);
		}
	    }
	}

    } // end rebuildSubProfiles


    public String updateRightSubProps(String rightObj) {

	if (isProfListOK) {
	    Vector<String> vAssignedProfs = new Vector<String>();

	    // Get the first generation children that are assigned to
	    // current profile.
	    DblTreeNode root = (DblTreeNode)dstModel.getRoot();
	    Enumeration kids;
	    kids = root.children();

	    while (kids.hasMoreElements()) {
		DblTreeNode childNode;
		childNode = (DblTreeNode)kids.nextElement();
		vAssignedProfs.addElement(childNode.toString());
	    }

	    // ProfAttrObj profAttr = rightObj.getProfAttr();
	    // profAttr.setProfNamesVector(vAssignedProfs);
	}
	return (rightObj);

    } // end updateRightSubProps

    public Vector<String> getAssignedProfs() {
	Vector<String> vAssignedProfs = new Vector<String>();

	if (!isProfListOK) {
	    return vAssignedProfs;
	}

	// Get the first generation children that are assigned to
	// current profile.
	DblTreeNode root = (DblTreeNode)dstModel.getRoot();
	Enumeration kids;
	kids = root.children();
	while (kids.hasMoreElements()) {
	    DblTreeNode childNode;
	    childNode = (DblTreeNode)kids.nextElement();
	    vAssignedProfs.addElement(childNode.toString());
	}

	return vAssignedProfs;
    }

    private Vector<String> getAvailableProfs() {
        Vector<String> rights = new Vector<String>();
	for (String s : panelDesc.getProfiles()) {
	    rights.add(s);

	}
    	return (rights);
    }

    public void setUser(UserManagedObject userObj) {
    	this.userObj = userObj;
	loadProfiles();
    }

    public UserManagedObject updateUser() {
        Vector<String> vProfs = getAssignedProfs();
	String profStr;

	if (vProfs.size() > 0) {
		profStr = vProfs.elementAt(0);
	} else {
		profStr = "";
	}

	for (int i = 1; i < vProfs.size(); i++) {
	    profStr = profStr.concat(",");
	    profStr = profStr.concat(vProfs.elementAt(i));
        }

	userObj.getAuthRightsProperty().setValue(profStr);

	return (userObj);
    }



class ProfileRenderer extends DefaultTreeCellRenderer {

    private boolean selected;
    Icon warningIcon;
    AuthRightsPanel rightsPanel;

    public ProfileRenderer(AuthRightsPanel rightsPanel) {

	this.rightsPanel = rightsPanel;
	setClosedIcon(null);
	setOpenIcon(null);
	setLeafIcon(null);
    	warningIcon = Finder.getIcon("images/warning.gif");

    }


    public Component getTreeCellRendererComponent(
	JTree tree,
	Object value,
	boolean selected,
	boolean expanded,
	boolean leaf,
	int row,
	boolean hasFocus) {

	FocusEvent e = null;

	this.selected = selected;

	DefaultTreeCellRenderer cr =
	    (DefaultTreeCellRenderer)tree.getCellRenderer();
	cr.setLeafIcon(null);
	DblTreeNode node = (DblTreeNode)value;

	if (node.getParent() == null) {
	    // maybe the same as row == 0
	    setText(node.toString());

	} else if (node.getUserObject() instanceof ProfTreeNode) {
	    ProfTreeNode profsdef = (ProfTreeNode)node.getUserObject();
	    setText(profsdef.toString());
	    // setIcon(actionIcon);

	    if (node.isConflict())
		if (tree == rightsPanel.profPanel.dstTree)
		    cr.setLeafIcon(warningIcon);
	}

	super.getTreeCellRendererComponent(tree, value, selected, expanded,
	    leaf, row, hasFocus);

	return this;

    } // end getTreeCellRendererComponent

}

class ProfTreeNode {

    String name;
    String rightObj = null;

    public ProfTreeNode(String rightObj) {
	this.rightObj = rightObj;
	this.name = rightObj;
    }

    public String getRightObj() {
	return rightObj;
    }

    public String toString() {
	return name;
    }

}

class NodeCompare implements Compare {

    /**
     * The compare method compares two ProfTreeNode objects by comparing
     * their profile names.  The parameters are specified as Object class
     * objects for QuickSort.
     *
     * @param   a	The first Node.
     * @param   b	The second Node.
     *
     */
    public final int doCompare(Object a, Object b) {

	ProfTreeNode e1, e2;
	String e1Name, e2Name;

	e1 = (ProfTreeNode)a;
	e2 = (ProfTreeNode)b;
	e1Name = e1.toString();
	e2Name = e2.toString();
	return (e1Name.compareTo(e2Name));

    }

}
}