// // ERXNavigationItem.java // ERExtensions // // Created by Max Muller on Wed Oct 30 2002. // package er.extensions.appserver.navigation; import java.io.Serializable; import java.util.Enumeration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.eocontrol.EOQualifier; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSKeyValueCodingAdditions; import com.webobjects.foundation.NSMutableArray; import er.extensions.foundation.ERXValueUtilities; /** * A "backing store" for the properties of a single navigation item in the tree * of navigation items. Configured by the {@link ERXNavigationManager * ERXNavigationManager} from a dictionary stored in the navigation menu plist * file. * * Please read "Documentation/Navigation.html" to fnd out how to use the * navigation components. * * @see ERXNavigationManager * @see ERXNavigationMenuItem */ public class ERXNavigationItem implements Serializable { /** * Do I need to update serialVersionUID? See section 5.6 <cite>Type Changes * Affecting Serialization</cite> on page 51 of the <a * href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object * Serialization Spec</a> */ private static final long serialVersionUID = 1L; private static int counter = 0; private static final Logger log = LoggerFactory.getLogger(ERXNavigationItem.class); public String _uniqueID; protected String _action; protected NSArray _conditions; protected EOQualifier _qualifier; protected String _directActionName; protected String _directActionClass; protected String _name; protected String _pageName; protected String _displayName; protected String _hasActivity; protected NSArray<String> _children; protected String _defaultChild; protected NSArray _childrenConditions; protected String _childrenBinding; protected NSDictionary _childrenChoices; protected NSDictionary _queryBindings; protected String _href; protected String _secure; protected ERXNavigationItem _parent; protected int _height; protected int _width; public ERXNavigationItem(NSDictionary values) { // set uniqueID _uniqueID = "id" + counter; counter++; if (values != null) { log.debug("ERXNavigationItem {} assigned these values at creation:\n{}", uniqueID(), values); _action = (String) values.valueForKey("action"); _conditions = NSArray.EmptyArray; Object o = values.valueForKey("conditions"); if (o != null) { if (o instanceof NSArray) { _conditions = (NSArray) o; } else if (o instanceof String) { _conditions = NSArray.componentsSeparatedByString((String) o, ","); } } o = values.valueForKey("qualifier"); if (o instanceof String && ((String) o).trim().length() > 0) { _qualifier = EOQualifier.qualifierWithQualifierFormat((String) o, null); } _href = (String) values.valueForKey("href"); _directActionName = (String) values.valueForKey("directActionName"); _directActionClass = (String) values.valueForKey("directActionClass"); if (values.valueForKey("height") != null) _height = Integer.valueOf((String) values.valueForKey("height")).intValue(); if (values.valueForKey("width") != null) _width = Integer.valueOf((String) values.valueForKey("width")).intValue(); _name = (String) values.valueForKey("name"); _defaultChild = (String) values.valueForKey("defaultChild"); _displayName = (String) values.valueForKey("displayName"); if (_displayName == null || _displayName.length() == 0) _displayName = _name; _pageName = (String) values.valueForKey("pageName"); _secure = (String) values.valueForKey("secure"); _hasActivity = (String) values.valueForKey("hasActivity"); if (values.valueForKey("children") != null && values.valueForKey("children") instanceof NSArray) { _children = (NSArray) values.valueForKey("children"); } else if (values.valueForKey("children") != null && values.valueForKey("children") instanceof String) { _childrenBinding = (String) values.valueForKey("children"); } else { _children = NSArray.EmptyArray; } if (values.valueForKey("childrenChoices") != null) { _childrenChoices = (NSDictionary) values.valueForKey("childrenChoices"); } else { _childrenChoices = NSDictionary.EmptyDictionary; } if (values.valueForKey("queryBindings") != null) { _queryBindings = (NSDictionary) values.valueForKey("queryBindings"); } else { _queryBindings = NSDictionary.EmptyDictionary; } if (values.valueForKey("childrenConditions") == null || ((String) values.valueForKey("childrenConditions")).equals("")) { _childrenConditions = NSArray.EmptyArray; } else { _childrenConditions = NSArray.componentsSeparatedByString((String) values.valueForKey("childrenConditions"), ","); } } else { log.warn("Constructing a ERXNavigationItem with a null dictionary!"); } } /** * Decides whether the item gets displayed at all. This is done by * evaluating the boolean value of a "conditions" array in the definition * file. eg: conditions = ("session.user.canEditThisStuff", * "session.user.isEditor") will display the item only if the user can edit * this stuff *and* is an editor. You can set OR conditions with conditions * = (("session.user.canEditThisStuff", "session.user.isEditor")) * * @param context * in which to evaluate visibility * @return true if the item meets display conditions */ public boolean meetsDisplayConditionsInComponent(NSKeyValueCodingAdditions context) { Boolean meetsDisplayConditions = Boolean.TRUE; if (conditions().count() != 0) { Enumeration enumerator = conditions().objectEnumerator(); while (enumerator.hasMoreElements()) { Object possibleKey = enumerator.nextElement(); if (possibleKey instanceof String) { String anObject = (String) possibleKey; Object value = context.valueForKeyPath(anObject); meetsDisplayConditions = ERXValueUtilities.booleanValue(value) ? Boolean.TRUE : Boolean.FALSE; log.debug("{} testing display condition: {} --> {}:{}", name(), anObject, value, meetsDisplayConditions); if (!meetsDisplayConditions.booleanValue()) { break; } } else { boolean temp = false; Enumeration e2 = ((NSArray) possibleKey).objectEnumerator(); while (e2.hasMoreElements()) { String key = (String) e2.nextElement(); Object value = context.valueForKeyPath(key); temp |= ERXValueUtilities.booleanValue(value); if (temp) { break; } log.debug("{} testing display condition: {} --> {}:{}", name(), key, value, meetsDisplayConditions); } meetsDisplayConditions = temp ? Boolean.TRUE : Boolean.FALSE; if (!meetsDisplayConditions.booleanValue()) { break; } } } if (meetsDisplayConditions.booleanValue() && qualifier() != null) { meetsDisplayConditions = qualifier().evaluateWithObject(this) ? Boolean.TRUE : Boolean.FALSE; } } return meetsDisplayConditions.booleanValue(); } public NSArray childItemsInContext(NSKeyValueCodingAdditions context) { NSArray children = null; NSArray childrenConditions = childrenConditions(); boolean hasChildrenConditions = childrenConditions.count() != 0; boolean meetsChildrenConditions = true; if (hasChildrenConditions) { for (Enumeration e = childrenConditions.objectEnumerator(); e.hasMoreElements();) { String aCondition = (String) e.nextElement(); meetsChildrenConditions = ERXValueUtilities.booleanValue(context.valueForKeyPath(aCondition)); if (!meetsChildrenConditions) break; } } if (meetsChildrenConditions) { /* * only want to do this if childrenConditions are met, or if there * aren't any children conditions */ if (children() != null) { children = children(); } else if (childrenBinding() != null) { Object o = context.valueForKeyPath(childrenBinding()); if (o != null && o instanceof NSArray) { children = (NSArray) o; } else if (o != null && o instanceof String) { children = (NSArray) childrenChoices().objectForKey(o); if (children == null) { log.warn("For nav core object: {} and child binding: {} couldn't find children for choice key: {}", this, childrenBinding(), o); } } else { log.warn("For nav core object: {} and child binding: {} received binding object: {}", this, childrenBinding(), o); } } } if (children == null) { children = NSArray.EmptyArray; } if (children.count() > 0) { NSMutableArray childNavItems = new NSMutableArray(); for (Enumeration e = children.objectEnumerator(); e.hasMoreElements();) { String childName = (String) e.nextElement(); ERXNavigationItem item = ERXNavigationManager.manager().navigationItemForName(childName); if (item != null) { /* * since same child node can be shared by multiple parents * setParent is differed until now. every time children are * asked for, 'this' parent is set on them. */ item.setParent(this); childNavItems.addObject(item); } else { log.warn("Unable to find navigation item for name: {}", childName); } } children = childNavItems; } return children; } public Boolean secureInContext(NSKeyValueCodingAdditions context) { if(_secure == null) { return null; } Object value = _secure; if(_secure.indexOf('.') > -1) { value = context.valueForKeyPath(_secure); } return ERXValueUtilities.BooleanValueWithDefault(value, null); } public boolean isRootNode() { return this == ERXNavigationManager.manager().rootNavigationItem(); } public NSArray<String> children() { return _children; } public EOQualifier qualifier() { return _qualifier; } public String childrenBinding() { return _childrenBinding; } public NSArray childrenConditions() { return _childrenConditions; } public NSDictionary childrenChoices() { return _childrenChoices; } public String defaultChild() { return _defaultChild; } public void setDefaultChild(String name) { _defaultChild = name; } public NSDictionary queryBindings() { return _queryBindings; } public String action() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).action(); } return _action; } public NSArray conditions() { return _conditions; } public String href() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).href(); } return _href; } public String directActionName() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).directActionName(); } return directActionClass() == null ? _directActionName : directActionClass() + "/" + _directActionName; } public String uneditedDirectActionName() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).uneditedDirectActionName(); } return _directActionName; } public String directActionClass() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).directActionClass(); } return _directActionClass; } public int height() { return _height; } public int width() { return _width; } public String name() { return _name; } public String pageName() { if (defaultChild() != null) { return ERXNavigationManager.manager().navigationItemForName(defaultChild()).pageName(); } return _pageName; } public String uniqueID() { return _uniqueID; } public String displayName() { return _displayName; } public String hasActivity() { return _hasActivity; } @Override public String toString() { return "< " + name() + " >"; } public ERXNavigationItem parent() { return _parent; } public void setParent(ERXNavigationItem item) { _parent = item; } /** * Returns path of this navigationMenuItem starting from the top menu except * the root navigation item separated by /. ex: * topMenuItem/secondlevelmenuitem/thirdlevelnavItem NOTE: navigationPath * doesn't include rootNavigationItem. * * @return {@link String} navigationPath */ public String navigationPath() { StringBuilder result = new StringBuilder(); // local variable to keep track of the navItem in the loop ERXNavigationItem navItem = this; result.append(navItem.name()); while (navItem.parent() != null && navItem.parent() != ERXNavigationManager.manager().rootNavigationItem()) { navItem = navItem.parent(); result.insert(0, navItem.name() + "/"); } return result.toString(); } }