You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/04/09 12:48:00 UTC
svn commit: r763596 - in /myfaces/trinidad/branches/1.2.11.2-branch:
trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/
trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/
Author: matzew
Date: Thu Apr 9 10:48:00 2009
New Revision: 763596
URL: http://svn.apache.org/viewvc?rev=763596&view=rev
Log:
TRINIDAD-708 - NullPointerException with multiple XMLMenuModel beans in one page
Thanks to Abhijit S Ghosh for his patch
Added:
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableGroupNode.java
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableItemNode.java
Modified:
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ItemNode.java
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java
myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java
Modified: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java?rev=763596&r1=763595&r2=763596&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java (original)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java Thu Apr 9 10:48:00 2009
@@ -24,13 +24,18 @@
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -81,6 +86,8 @@
* </managed-bean>
* </pre>
*
+ * Objects of this class are not thread safe and should be used
+ * only in request scope.
*
*/
@@ -130,7 +137,7 @@
* have the currently selected node!
*/
public class XMLMenuModel extends BaseMenuModel
- implements Serializable
+
{
public XMLMenuModel()
{
@@ -169,7 +176,7 @@
// There is no need to create the hashmaps or anything
// on the child menu models. A lot of overhead (performance and
// memory) would be wasted.
- if (this == _getRootModel())
+ if (_isRoot)
{
_viewIdFocusPathMap = _contentHandler.getViewIdFocusPathMap(_mdSource);
_nodeFocusPathMap = _contentHandler.getNodeFocusPathMap(_mdSource);
@@ -565,7 +572,7 @@
*/
public Map<String, List<Object>> getViewIdFocusPathMap()
{
- if (this != _getRootModel() || _contentHandler == null)
+ if (!_isRoot || _contentHandler == null)
return null;
if (_viewIdFocusPathMap == null)
@@ -574,13 +581,60 @@
return _viewIdFocusPathMap;
}
+ /**
+ * Returns the map of content handlers
+ * which hold the state of one XML tree.
+ * @param scopeMap
+ * @return
+ */
+ protected Map<Object, List<MenuContentHandler> > getContentHandlerMap()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Map<String, Object> scopeMap =
+ externalContext.getApplicationMap();
+ Object lock = externalContext.getContext();
+
+ // cannot use double checked lock here as
+ // we cannot mark the reference as volatile
+ // therefore any reads should happen inside
+ // a synchronized block.
+ synchronized (lock)
+ {
+ Map contentHandlerMap = (Map) scopeMap.get(_CACHED_MODELS_KEY);
+ if (contentHandlerMap == null)
+ {
+ contentHandlerMap =
+ new ConcurrentHashMap<String, List<MenuContentHandler>>();
+ scopeMap.put(_CACHED_MODELS_KEY, contentHandlerMap);
+ scopeMap.put(_CACHED_MODELS_ID_CNTR_KEY,new AtomicInteger(-1));
+ }
+ return contentHandlerMap;
+ }
+
+ }
+
+ protected int getContentHandlerId()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Map<String, Object> scopeMap =
+ externalContext.getApplicationMap();
+ AtomicInteger counter = (AtomicInteger) scopeMap.get(_CACHED_MODELS_ID_CNTR_KEY);
+ return counter.getAndIncrement();
+ }
+ protected Object getCacheKey()
+ {
+ return _mdSource;
+ }
+
/* ====================================================================
* Private Methods
* ==================================================================== */
private Map<String, Object> _getIdNodeMap()
{
- return (this == _getRootModel()) ? _idNodeMap : null;
+ return (_isRoot) ? _idNodeMap : null;
}
/**
@@ -613,7 +667,33 @@
{
try
{
- if (_contentHandler == null)
+ // this block of code handles the injection of the
+ // correct content handler for this xml menu model.
+ _isRoot = _isThisRootModel();
+
+ boolean newHandlerCreated = false;
+ List<MenuContentHandler> listOfHandlers = getContentHandlerMap().get(getCacheKey());
+ Map<Integer,XMLMenuModel> requestModelMap = _getRootModelMap();
+ if(listOfHandlers != null)
+ {
+ if(requestModelMap == null)
+ _contentHandler = listOfHandlers.get(0);
+ else
+ {
+
+ for (MenuContentHandler handler : listOfHandlers)
+ {
+ int id = handler.getId();
+ if (!requestModelMap.containsKey(id))
+ {
+ _contentHandler = handler;
+ break;
+ }
+ }
+ }
+ }
+
+ if(_contentHandler == null)
{
List<MenuContentHandler> services =
ClassLoaderUtils.getServices(_MENUCONTENTHANDLER_SERVICE);
@@ -629,18 +709,59 @@
{
throw new NullPointerException();
}
+ newHandlerCreated = true;
+ }
+
+ if(_isRoot)
+ {
+ if(listOfHandlers == null)
+ {
+ listOfHandlers = Collections.synchronizedList(new ArrayList<MenuContentHandler>());
+ getContentHandlerMap().put(getCacheKey(), listOfHandlers);
+ }
+ if(newHandlerCreated)
+ {
+ listOfHandlers.add(_contentHandler);
+ _contentHandler.setRootHandler(true);
+ _contentHandler.setId(getContentHandlerId());
+ }
+
}
// Set the root, top-level menu model's URI on the contentHandler.
// In this model, the menu content handler and nodes need to have
// access to the model's data structures and to notify the model
// of the currently selected node (in the case of a POST).
+ _populateRootModelMap();
_setRootModelKey(_contentHandler);
// Set the local model (model created by a sharedNode) on the
// contentHandler so that nodes can get back to their local model
// if necessary.
- _setModelId(_contentHandler);
+
+ // Nodes never get back to their local models,which is good
+ // because if they did they would not have found them as the
+ // hash code of newly created XMLMenuModels would be different
+ // and hence the modelIds of the menu nodes would be stale
+ // as they are longer lived than the menu models
+
+ // On the other hand the content handler does refer to it's
+ // local model during parsing at which time it is guaranteed
+ // to be referring to just one model due to synchronization
+ // of the parsing activity.
+
+ // Therefore we only set the model id if this is a newly
+ // created content handler,as we know it will start parsing
+ // shortly.This is also necessary so that the model id of
+ // the content handler does not change during the time it
+ // is initializing it's state by parsing.Thus we can do
+ // without synchronization here as the protection is needed only during
+ // parsing.Any other request thread for the same meta-data URI will
+ // find the content handler already published on the concurrent hash map
+ // of content handlers.
+
+ if(newHandlerCreated)
+ _setModelId(_contentHandler);
TreeModel treeModel = _contentHandler.getTreeModel(_mdSource);
setWrappedData(treeModel);
@@ -653,6 +774,7 @@
}
}
+
/**
* _setRootModelKey - sets the top-level, menu model's Key on the
* menu content handler. This is so nodes will only operate
@@ -662,22 +784,43 @@
@SuppressWarnings("unchecked")
private void _setRootModelKey(MenuContentHandler contentHandler)
{
- if (_getRootModel() == null)
+ contentHandler.setRootModelKey(_ROOT_MODEL_KEY);
+ }
+
+
+ /*
+ * sets the model into the requestMap
+ */
+ private void _populateRootModelMap()
+ {
+ if (_isRoot)
{
- // Put the root model on the Request Map so that it
- // Can be picked up by the nodes to call back into the
- // root model
- FacesContext facesContext = FacesContext.getCurrentInstance();
- Map<String, Object> requestMap =
- facesContext.getExternalContext().getRequestMap();
-
- requestMap.put(_ROOT_MODEL_KEY, this);
-
- // Set the key to the root model on the content
- // handler so that it can then be set on each of the nodes
- contentHandler.setRootModelKey(_ROOT_MODEL_KEY);
+ Map<String, Object> requestMap = _getRequestMap();
+ Map<Integer, XMLMenuModel> modelMap =
+ (Map<Integer, XMLMenuModel>) requestMap.get(_ROOT_MODEL_KEY);
+ if(modelMap == null)
+ {
+ modelMap = new HashMap<Integer,XMLMenuModel>();
+ requestMap.put(_ROOT_MODEL_KEY, modelMap);
+ }
+ modelMap.put(_contentHandler.getId(), this);
}
}
+
+ private boolean _isThisRootModel()
+ {
+ Map<String, Object> requestMap = _getRequestMap();
+ return !requestMap.containsKey(SHARED_MODEL_INDICATOR_KEY);
+ }
+
+ private Map<String, Object> _getRequestMap()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Map<String, Object> requestMap =
+ facesContext.getExternalContext().getRequestMap();
+ return requestMap;
+ }
+
/**
* Returns the root menu model.
@@ -687,10 +830,17 @@
@SuppressWarnings("unchecked")
private XMLMenuModel _getRootModel()
{
+ Map<Integer, XMLMenuModel> map = _getRootModelMap();
+ return map.get(_contentHandler.getId());
+ }
+
+ private Map<Integer,XMLMenuModel> _getRootModelMap()
+ {
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String, Object> requestMap =
facesContext.getExternalContext().getRequestMap();
- return (XMLMenuModel) requestMap.get(_ROOT_MODEL_KEY);
+ Map<Integer,XMLMenuModel> map = (Map<Integer,XMLMenuModel>) requestMap.get(_ROOT_MODEL_KEY);
+ return map;
}
@@ -833,6 +983,20 @@
* @return the Model's viewIdFocusPathMap
*/
public Map<String, List<Object>> getViewIdFocusPathMap(Object modelKey);
+
+ public void setRootHandler(boolean isRoot);
+
+ /**
+ * sets the id of this content handler
+ */
+ public void setId(int id);
+
+ /**
+ * gets the id of this content handler
+ * @return the id
+ */
+ public int getId();
+
}
private Object _currentNode = null;
@@ -847,13 +1011,31 @@
private Map<Object, List<Object>> _nodeFocusPathMap;
private Map<String, Object> _idNodeMap;
- static private MenuContentHandler _contentHandler = null;
+ private MenuContentHandler _contentHandler = null;
+ private boolean _isRoot;
+
// Only set this if _currentNode is a duplicate
- static private Object _prevRequestNode = null;
+ private Object _prevRequestNode = null;
+ // this key is used to store the map of models in the request.
static private final String _ROOT_MODEL_KEY =
"org.apache.myfaces.trinidad.model.XMLMenuModel.__root_menu__";
+
+ // this key is used to store the map of content handlers in the scope map
+ static private final String _CACHED_MODELS_KEY =
+ "org.apache.myfaces.trinidad.model.XMLMenuModel.__handler_key__";
+
+ // this supplies the id of the content handlers
+ static private final String _CACHED_MODELS_ID_CNTR_KEY =
+ "org.apache.myfaces.trinidad.model.XMLMenuModel.__id_cntr_key__";
+
+/**
+ * This key is used to store information about the included xml menu
+ * models which are constructed during parsing.
+ */
+ static public final String SHARED_MODEL_INDICATOR_KEY =
+ "org.apache.myfaces.trinidad.model.XMLMenuModel.__indicator_key__";
static private final String _NODE_ID_PROPERTY = "nodeId";
static private final String _METHOD_GET = "get";
@@ -865,5 +1047,5 @@
static private final TrinidadLogger _LOG =
TrinidadLogger.createTrinidadLogger(XMLMenuModel.class);
- private static final long serialVersionUID = 1L;
+
}
Modified: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java?rev=763596&r1=763595&r2=763596&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java (original)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java Thu Apr 9 10:48:00 2009
@@ -191,7 +191,18 @@
{
return _idref;
}
+
+ public String[] getIdRefListProperty()
+ {
+ return _idrefList;
+ }
+ @Override
+ protected MenuNode getThreadSafeCopy()
+ {
+ return new ImmutableGroupNode(this);
+ }
+
/* =============================================================
* Private methods
* =============================================================*/
Added: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableGroupNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableGroupNode.java?rev=763596&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableGroupNode.java (added)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableGroupNode.java Thu Apr 9 10:48:00 2009
@@ -0,0 +1,549 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.trinidadinternal.menu;
+
+import java.lang.reflect.Array;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * This class is a thread safe version of GroupNode class.
+ * It replicates most of the code in GroupNode but makes
+ * sure it does not modify state of the object.
+ *
+ * Therefore multiple request threads can access the
+ * properties of the objects of this class,in a thread safe
+ * manner.
+ *
+ * Please note that setters should not be called on objects
+ * of this class.Objects of this class are fully initialized
+ * on construction.
+ *
+ */
+public class ImmutableGroupNode extends GroupNode
+{
+
+ public ImmutableGroupNode(GroupNode node)
+ {
+ _icon = node.getIconProperty();
+ _focusViewId = node.getFocusViewIdProperty();
+ _renderedStr = node.getRenderedProperty();
+ _disabledStr = node.getDisabledProperty();
+ _visibleStr = node.getVisibleProperty();
+ _readOnlyStr = node.getReadOnlyProperty();
+ _handlerId = node.getHandlerIdProperty();
+ _bundleKey = node.getBundleKeyProperty();
+ _bundleName = node.getBundleNameProperty();
+ _accessKey = node.getAccessKeyProperty();
+ _id = node.getIdProperty();
+ _modelId = node.getModelIdProperty();
+ _labelAndAccessKey = node.getLabelAndAccessKeyProperty();
+ _defaultFocusPathStr = node.getDefaultFocusPathProperty();
+
+ // Root Menu model's Request Map Key
+ _rootModelKey = node.getRootModelKeyProperty();
+
+ _rootId = node.getRootIdProperty();
+ _label = node.getLabelProperty();
+ _idref = node.getIdRef();
+ _idrefList = node.getIdRefListProperty();
+ }
+
+
+ public String getIdRef()
+ {
+ return _idref;
+ }
+
+ public MenuNode getRefNode()
+ {
+ MenuNode refNode = null;
+
+
+ // Get idrefList
+ String[] idrefList = _idrefList;
+
+ // get group node's children
+ List<MenuNode> children = getChildren();
+
+ // Traverse the list. Do the following:
+ // o get Node from Model's hashMap of nodes and ids
+ // o check attributes (rendered, disabled, readOnly)
+ // o if they are ok, return the node
+ for (int i=0; i < Array.getLength(idrefList); i++)
+ {
+ Iterator<MenuNode> childIter = children.iterator();
+
+ // All node "id" attribute values had the node's
+ // system hashcode id appended to the id when
+ // placed in the model's idNodeMap.
+ //
+ // Each id in the idreflist of a group node does
+ // NOT have this node sys id appended it to it
+ // and needs to or we won't find the group's
+ // ref node.
+ //
+ // Since group nodes can only point to one of
+ // its children, we iterate through them, get
+ // their sys id and append it to idref until
+ // we find a match (or not).
+ while (childIter.hasNext())
+ {
+ MenuNode childNode = childIter.next();
+ String modelId = childNode.getModelId();
+
+ // Need to append mode's sys id here to create a
+ // unique id.
+ String refNodeId = idrefList[i] + modelId;
+
+ refNode = (MenuNode) getRootModel().getNode(refNodeId);
+
+ // if nothing found, move on to the next child
+ if (refNode != null)
+ break;
+ }
+
+ if (refNode == null)
+ continue;
+
+ // Check the attributes of the found node
+ if ( !refNode.getRendered()
+ || refNode.getDisabled()
+ || refNode.getReadOnly()
+ || !refNode.getVisible()
+ )
+ {
+ refNode = null;
+ continue;
+ }
+
+ // Ok, we have a valid RefNode
+ break;
+ }
+
+ // If no valid node is found,
+ // log an error
+ if (refNode == null)
+ {
+ _LOG.severe("GroupNode " + getLabel() + " refers to no valid node.\n");
+ return null;
+ }
+
+ return refNode;
+ }
+
+ public final String getLabel()
+ {
+ if (_bundleKey != null && _bundleName != null)
+ {
+ // Load the resource bundle based on the locale of the
+ // current request. If the locale has not changed, this
+ // method just returns.
+ MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+ }
+
+ if (_label != null && ContainerUtils.isValueReference(_label))
+ {
+ // do not set _label to the evaluated EL.
+ // It may change at times in the EL.
+ return _evalElStr(_label);
+ }
+ if (_label == null && _labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ } else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ return label;
+
+ }
+ return _label;
+ }
+
+ public final String getIcon()
+ {
+ return MenuUtils.evalString(_icon);
+ }
+
+ public final List<MenuNode> getChildren()
+ {
+ return _children;
+ }
+
+ public final String getFocusViewId()
+ {
+ return _focusViewId;
+ }
+
+ public final boolean getRendered()
+ {
+ boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
+ return rendered;
+ }
+
+ public final boolean getDisabled()
+ {
+ boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
+ return disabled;
+ }
+
+ public final boolean getVisible()
+ {
+ boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
+ return visible;
+ }
+
+ public final boolean getReadOnly()
+ {
+ boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
+ return readOnly;
+ }
+
+ protected final String getHandlerId()
+ {
+ return _handlerId;
+ }
+
+ public final String getBundleKey()
+ {
+ return _bundleKey;
+ }
+
+ public final String getBundleName()
+ {
+ return _bundleName;
+ }
+
+
+
+
+
+ public final char getAccessKey()
+ {
+ if (_accessKey == null && _labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ }
+ else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey = null;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ return (accessKey != null)? accessKey.charAt(0):'\0';
+
+ }
+ else
+ {
+ String accessKeyStr = MenuUtils.evalString(_accessKey);
+ if (accessKeyStr == null || accessKeyStr.length() > 1)
+ return '\0';
+ return accessKeyStr.charAt(0);
+ }
+
+ }
+
+ public final String getLabelAndAccessKey()
+ {
+ if (_labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (_bundleKey != null && _bundleName != null)
+ {
+ // Load the resource bundle based on the locale of the
+ // current request. If the locale has not changed, this
+ // method just returns.
+ MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+ }
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ } else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey = null;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ if(accessKey == null)
+ return label;
+
+ return _joinLabelAndAccessKey(label, accessKey);
+ }
+ return null;
+ }
+ public final String getId()
+ {
+ return _id;
+ }
+
+ public final String getModelId()
+ {
+ return _modelId;
+ }
+
+ //TODO make this work
+// public final String getLabelAndAccessKey()
+// {
+// String labelAndAcessKeyEval;
+// if ( _labelAndAccessKey != null
+// && ContainerUtils.isValueReference(_labelAndAccessKey)
+// )
+// {
+// labelAndAcessKeyEval= _evalElStr(_labelAndAccessKey);
+// }
+// else
+// {
+// labelAndAcessKeyEval = _labelAndAccessKey;
+// }
+//
+//
+// }
+
+ public final boolean getDefaultFocusPath()
+ {
+ boolean defaultFocusPath =
+ MenuUtils.evalBoolean(_defaultFocusPathStr, false);
+ return defaultFocusPath;
+ }
+
+ public final String getRootModelKey()
+ {
+ return _rootModelKey;
+ }
+
+ public final int getRootId()
+ {
+ return _rootId;
+ }
+
+ private String _evalElStr(String str)
+ {
+ if (str == null)
+ return null;
+
+ String keystr =
+ MenuUtils.stringReplaceFirst(str.trim(), _bundleKey, _bundleKey +
+ getHandlerId());
+ String elVal = MenuUtils.getBoundValue(keystr, String.class);
+ return elVal;
+ }
+
+ private String _joinLabelAndAccessKey(String label, String accessKey)
+ {
+ char[] keyArray = label.toCharArray();
+ int len = label.length();
+ int lentimes2 = len * 2;
+ char[] keyArray2 = new char[lentimes2];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ // find the first occurrence of a single Ampersand
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ // AccessKey
+ if (keyArray[i] == accessKey.charAt(0) && !accessKeyFound)
+ {
+ keyArray2[j] = '&';
+ j++;
+ accessKeyFound = true;
+ }
+
+ keyArray2[j] = keyArray[i];
+
+ // Ampersand as regular character
+ // double it up.
+ if (keyArray[i] == '&')
+ {
+ j++;
+ keyArray2[j] = keyArray[i];
+ }
+ }
+
+ String combinedLabel = new String(keyArray2, 0, j);
+ return combinedLabel;
+ }
+
+ private final String _icon;
+ private List<MenuNode> _children;
+ private final String _focusViewId;
+ private final String _renderedStr;
+ private final String _disabledStr;
+ private final String _visibleStr;
+ private final String _readOnlyStr;
+ private final String _handlerId;
+ private final String _bundleKey;
+ private final String _bundleName;
+ private final String _accessKey;
+ private final String _id;
+ private final String _modelId;
+ private final String _labelAndAccessKey;
+ private final String _defaultFocusPathStr;
+
+ // Root Menu model's Request Map Key
+ private final String _rootModelKey;
+
+ private final int _rootId;
+
+
+
+ private final String _label;
+
+
+ private final String _idref ;
+ private final String[] _idrefList ;
+
+ private final static TrinidadLogger _LOG =
+ TrinidadLogger.createTrinidadLogger(ImmutableGroupNode.class);
+}
Added: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableItemNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableItemNode.java?rev=763596&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableItemNode.java (added)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ImmutableItemNode.java Thu Apr 9 10:48:00 2009
@@ -0,0 +1,621 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.menu;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * This class is a thread safe version of ItemNode class.
+ * It replicates most of the code in ItemNode but makes
+ * sure it does not modify state of the object.
+ *
+ * Therefore multiple request threads can access the
+ * properties of the objects of this class,in a thread safe
+ * manner.
+ *
+ * Please note that setters should not be called on objects
+ * of this class.Objects of this class are fully initialized
+ * on construction.
+ *
+ */
+public class ImmutableItemNode extends ItemNode
+{
+
+ public ImmutableItemNode(ItemNode node)
+ {
+ _icon = node.getIconProperty();
+ _focusViewId = node.getFocusViewIdProperty();
+ _renderedStr = node.getRenderedProperty();
+ _disabledStr = node.getDisabledProperty();
+ _visibleStr = node.getVisibleProperty();
+ _readOnlyStr = node.getReadOnlyProperty();
+ _handlerId = node.getHandlerIdProperty();
+ _bundleKey = node.getBundleKeyProperty();
+ _bundleName = node.getBundleNameProperty();
+ _accessKey = node.getAccessKeyProperty();
+ _id = node.getIdProperty();
+ _modelId = node.getModelIdProperty();
+ _labelAndAccessKey = node.getLabelAndAccessKeyProperty();
+ _defaultFocusPathStr = node.getDefaultFocusPathProperty();
+
+ // Root Menu model's Request Map Key
+ _rootModelKey = node.getRootModelKeyProperty();
+
+ _rootId = node.getRootIdProperty();
+
+ _customPropList = node.getCustomPropListProperty();
+
+ _destination = node.getDestinationProperty();
+ _targetFrame = node.getTargetFrameProperty();
+ _action = node.getActionProperty();
+ _actionListener = node.getActionListenerProperty();
+ _launchListener = node.getLaunchListenerProperty();
+ _returnListener = node.getReturnListenerProperty();
+ _immediateStr = node.getImmediateProperty();
+ _useWindowStr = node.getUseWindowProperty();
+ _windowHeightStr = node.getWindowHeightProperty();
+ _windowWidthStr = node.getWindowWidthProperty();
+
+ _label = node.getLabelProperty();
+ }
+
+ public final Map<String, String> getCustomPropList()
+ {
+ return _customPropList;
+ }
+
+ public final String getDestination()
+ {
+
+ String value = _destination;
+
+ // Could be EL expression
+ if (value != null && ContainerUtils.isValueReference(value))
+ {
+ // Value of action is EL method binding, so we
+ // need to evaluate it
+ value = MenuUtils.getBoundValue(value, String.class);
+ }
+
+ // Appending nodeId to URL so that we can identify the node
+ // when getFocusRowKey() is called on the model.
+ return value != null ? value + "?nodeId=" + getUniqueId() : value;
+
+ }
+
+ public final String getTargetFrame()
+ {
+ String value = _targetFrame;
+
+ // Could be EL expression
+ if (value != null && ContainerUtils.isValueReference(value))
+ {
+ // Value of destination is EL value binding, so we
+ // need to evaluate it
+ value = MenuUtils.getBoundValue(value, String.class);
+ }
+
+ return value;
+ }
+
+ public final String getActionListener()
+ {
+ String value = _actionListener;
+
+ // Could be EL expression
+ if (value != null && ContainerUtils.isValueReference(value))
+ {
+ // Value of action is EL method binding, so we
+ // need to evaluate it
+ value = MenuUtils.getBoundValue(value, String.class);
+ }
+
+ return value;
+ }
+
+ public final String getLaunchListener()
+ {
+
+ String value = _launchListener;
+
+ // Could be EL expression
+ if (value != null && ContainerUtils.isValueReference(value))
+ {
+ // Value of action is EL method binding, so we
+ // need to evaluate it
+ value = MenuUtils.getBoundValue(value, String.class);
+ }
+
+ return value;
+ }
+
+ public final String getReturnListener()
+ {
+ String value = _returnListener;
+
+ // Could be EL expression
+ if (value != null && ContainerUtils.isValueReference(value))
+ {
+ // Value of action is EL method binding, so we
+ // need to evaluate it
+ value = MenuUtils.getBoundValue(value, String.class);
+ }
+
+ return value;
+
+ }
+
+ public final boolean getImmediate()
+ {
+ boolean immediate = MenuUtils.evalBoolean(_immediateStr, false);
+ return immediate;
+ }
+
+ public final boolean getUseWindow()
+ {
+ boolean useWindow = MenuUtils.evalBoolean(_useWindowStr, false);
+ return useWindow;
+ }
+
+ public final int getWindowHeight()
+ {
+ int windowHeight = MenuUtils.evalInt(_windowHeightStr);
+ return windowHeight;
+ }
+
+ public final int getWindowWidth()
+ {
+ int windowWidth = MenuUtils.evalInt(_windowWidthStr);
+ return windowWidth;
+ }
+
+ public final String getLabel()
+ {
+ if (_bundleKey != null && _bundleName != null)
+ {
+ // Load the resource bundle based on the locale of the
+ // current request. If the locale has not changed, this
+ // method just returns.
+ MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+ }
+
+ if (_label != null && ContainerUtils.isValueReference(_label))
+ {
+ // do not set _label to the evaluated EL.
+ // It may change at times in the EL.
+ return _evalElStr(_label);
+ }
+ if (_label == null && _labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ } else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ return label;
+
+ }
+ return _label;
+ }
+
+ public final String getIcon()
+ {
+ return MenuUtils.evalString(_icon);
+ }
+
+ public final List<MenuNode> getChildren()
+ {
+ return _children;
+ }
+
+ public void setChildren(List<MenuNode> children)
+ {
+ _children = children;
+ }
+
+ public final String getFocusViewId()
+ {
+ return _focusViewId;
+ }
+
+ public final boolean getRendered()
+ {
+ boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
+ return rendered;
+ }
+
+ public final boolean getDisabled()
+ {
+ boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
+ return disabled;
+ }
+
+ public final boolean getVisible()
+ {
+ boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
+ return visible;
+ }
+
+ public final boolean getReadOnly()
+ {
+ boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
+ return readOnly;
+ }
+
+ protected final String getHandlerId()
+ {
+ return _handlerId;
+ }
+
+ public final String getBundleKey()
+ {
+ return _bundleKey;
+ }
+
+ public final String getBundleName()
+ {
+ return _bundleName;
+ }
+
+ public void actionListener(ActionEvent event)
+ {
+ String value = _actionListener;
+ if (value != null)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExpressionFactory expressionFactory =
+ facesContext.getApplication().getExpressionFactory();
+ ELContext context = facesContext.getELContext();
+
+ MethodExpression methodExpression =
+ expressionFactory.createMethodExpression(context, value, Void.TYPE,
+ new Class<?>[]
+ { ActionEvent.class });
+ methodExpression.invoke(context, new Object[]
+ { event });
+ }
+
+ }
+
+ public String doAction()
+ {
+ String value = _action;
+
+ if (value != null)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExpressionFactory expressionFactory =
+ facesContext.getApplication().getExpressionFactory();
+ ELContext context = facesContext.getELContext();
+ MethodExpression methodExpression =
+ expressionFactory.createMethodExpression(context, value,
+ String.class, new Class<?>[]
+ {});
+ value = (String) methodExpression.invoke(context, null);
+ }
+
+ // Post me as the selected Node for the request
+ postSelectedNode(this);
+
+ return value;
+ }
+
+ public final char getAccessKey()
+ {
+ if (_accessKey == null && _labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ }
+ else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey = null;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ return (accessKey != null)? accessKey.charAt(0):'\0';
+
+ }
+ else
+ {
+ String accessKeyStr = MenuUtils.evalString(_accessKey);
+ if (accessKeyStr == null || accessKeyStr.length() > 1)
+ return '\0';
+ return accessKeyStr.charAt(0);
+ }
+
+ }
+
+ public final String getId()
+ {
+ return _id;
+ }
+
+ public final String getModelId()
+ {
+ return _modelId;
+ }
+
+ public final String getLabelAndAccessKey()
+ {
+ String labelAndAcessKeyEval;
+ if (_labelAndAccessKey != null)
+ {
+ int ampIdx = 0;
+ String labelAndAccessKeyEval = null;
+ String labelAndAccessKey = _labelAndAccessKey;
+ String label;
+ if (_bundleKey != null && _bundleName != null)
+ {
+ // Load the resource bundle based on the locale of the
+ // current request. If the locale has not changed, this
+ // method just returns.
+ MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+ }
+ if (ContainerUtils.isValueReference(labelAndAccessKey))
+ {
+ labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+ } else
+ {
+ labelAndAccessKeyEval = labelAndAccessKey;
+ }
+
+ String accessKey = null;
+ if (labelAndAccessKeyEval == null ||
+ (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+ {
+ // String is null or a label w/o an accesskey
+ label = labelAndAccessKeyEval;
+ } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+ {
+ // & is last character, strip it.
+ label = labelAndAccessKeyEval.substring(0, ampIdx);
+ } else
+ {
+ // We have a string with an accessKey somewhere
+ char[] keyArray = labelAndAccessKeyEval.toCharArray();
+ int len = labelAndAccessKeyEval.length();
+ char[] keyArray2 = new char[len];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ if (keyArray[i] == '&')
+ {
+ i++;
+
+ if (!accessKeyFound && keyArray[i] != '&')
+ {
+ // We have our accessKey
+ accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+ accessKeyFound = true;
+ }
+ }
+
+ keyArray2[j] = keyArray[i];
+ }
+
+ String label1 = new String(keyArray2, 0, j);
+ label = label1;
+ }
+ return _joinLabelAndAccessKey(label, accessKey);
+ }
+ return null;
+ }
+
+ public final boolean getDefaultFocusPath()
+ {
+ boolean defaultFocusPath =
+ MenuUtils.evalBoolean(_defaultFocusPathStr, false);
+ return defaultFocusPath;
+ }
+
+ public final String getRootModelKey()
+ {
+ return _rootModelKey;
+ }
+
+ public final int getRootId()
+ {
+ return _rootId;
+ }
+
+ private String _evalElStr(String str)
+ {
+ if (str == null)
+ return null;
+
+ String keystr =
+ MenuUtils.stringReplaceFirst(str.trim(), _bundleKey, _bundleKey +
+ getHandlerId());
+ String elVal = MenuUtils.getBoundValue(keystr, String.class);
+ return elVal;
+ }
+
+ private String _joinLabelAndAccessKey(String label, String accessKey)
+ {
+ char[] keyArray = label.toCharArray();
+ int len = label.length();
+ int lentimes2 = len * 2;
+ char[] keyArray2 = new char[lentimes2];
+ int i, j = 0;
+ boolean accessKeyFound = false;
+
+ // find the first occurrence of a single Ampersand
+ for (i = 0, j = 0; i < len; i++, j++)
+ {
+ // AccessKey
+ if (keyArray[i] == accessKey.charAt(0) && !accessKeyFound)
+ {
+ keyArray2[j] = '&';
+ j++;
+ accessKeyFound = true;
+ }
+
+ keyArray2[j] = keyArray[i];
+
+ // Ampersand as regular character
+ // double it up.
+ if (keyArray[i] == '&')
+ {
+ j++;
+ keyArray2[j] = keyArray[i];
+ }
+ }
+
+ String combinedLabel = new String(keyArray2, 0, j);
+ return combinedLabel;
+ }
+
+ private final String _icon;
+ private List<MenuNode> _children;
+ private final String _focusViewId;
+ private final String _renderedStr;
+ private final String _disabledStr;
+ private final String _visibleStr;
+ private final String _readOnlyStr;
+ private final String _handlerId;
+ private final String _bundleKey;
+ private final String _bundleName;
+ private final String _accessKey;
+ private final String _id;
+ private final String _modelId;
+ private final String _labelAndAccessKey;
+ private final String _defaultFocusPathStr;
+
+ // Root Menu model's Request Map Key
+ private final String _rootModelKey;
+
+ private final int _rootId;
+
+ private final Map<String, String> _customPropList;
+
+ private final String _destination;
+ private final String _targetFrame;
+ private final String _action;
+ private final String _actionListener;
+ private final String _launchListener;
+ private final String _returnListener;
+ private final String _immediateStr;
+ private final String _useWindowStr;
+ private final String _windowHeightStr;
+ private final String _windowWidthStr;
+
+ private final String _label;
+
+}
Modified: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ItemNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ItemNode.java?rev=763596&r1=763595&r2=763596&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ItemNode.java (original)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/ItemNode.java Thu Apr 9 10:48:00 2009
@@ -454,6 +454,61 @@
return _customPropList;
}
+
+ public final Map<String, String> getCustomPropListProperty()
+ {
+ return _customPropList;
+ }
+
+ public final String getDestinationProperty()
+ {
+ return _destination;
+ }
+
+ public final String getTargetFrameProperty()
+ {
+ return _targetFrame;
+ }
+
+ public final String getActionProperty()
+ {
+ return _action;
+ }
+
+ public final String getActionListenerProperty()
+ {
+ return _actionListener;
+ }
+
+ public final String getLaunchListenerProperty()
+ {
+ return _launchListener;
+ }
+
+ public final String getReturnListenerProperty()
+ {
+ return _returnListener;
+ }
+
+ public final String getImmediateProperty()
+ {
+ return _immediateStr;
+ }
+
+ public final String getUseWindowProperty()
+ {
+ return _useWindowStr;
+ }
+
+ public final String getWindowHeightProperty()
+ {
+ return _windowHeightStr;
+ }
+
+ public final String getWindowWidthProperty()
+ {
+ return _windowWidthStr;
+ }
/**
* Set the list of custom attributes.
*
@@ -465,6 +520,11 @@
_customPropList = attrMap;
}
+ protected MenuNode getThreadSafeCopy()
+ {
+ return new ImmutableItemNode(this);
+ }
+
// Map for Custom attributes (properties)
private Map<String, String> _customPropList = null;
@@ -478,4 +538,6 @@
private String _useWindowStr = null;
private String _windowHeightStr = null;
private String _windowWidthStr = null;
+
+
}
Modified: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java?rev=763596&r1=763595&r2=763596&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java (original)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java Thu Apr 9 10:48:00 2009
@@ -20,8 +20,10 @@
import java.io.InputStream;
import java.io.IOException;
+import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -100,8 +102,9 @@
* selected.
*/
public class MenuContentHandlerImpl extends DefaultHandler
- implements MenuContentHandler
+ implements MenuContentHandler,Serializable
{
+
/**
* Constructs a Menu Content Handler.
*/
@@ -109,11 +112,6 @@
{
super();
- // Init the essential maps.
- _treeModelMap = new HashMap<String, TreeModel>();
- _viewIdFocusPathMapMap = new HashMap<Object, Map<String, List<Object>>>();
- _nodeFocusPathMapMap = new HashMap<Object, Map<Object, List<Object>>>();
- _idNodeMapMap = new HashMap<Object, Map<String, Object>>();
}
/**
@@ -234,8 +232,19 @@
// local model.
menuNode.setModelId(getModelId());
+ // menu nodes need to know how to refer
+ // back to the specific xml menu model
+ // so that they can mutate them.
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Map<String, Object> requestMap =
+ facesContext.getExternalContext().getRequestMap();
+ if(!requestMap.containsKey(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY))
+ menuNode.setRootId( (getId() ) );
+ else
+ menuNode.setRootId((Integer) requestMap.get(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY));
+
List<MenuNode> list = _menuNodes.get(_nodeDepth-1);
- list.add(menuNode);
+ list.add(menuNode.getThreadSafeCopy());
}
}
else if (_SHARED_NODE.equals(qualifiedElemName))
@@ -247,6 +256,20 @@
// recursively call into this MenuContentHandlerImpl when parsing the
// submenu's metadata.
String expr = attrList.getValue(_REF_ATTR);
+
+ // push this only when we are root model
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Map<String, Object> requestMap =
+ facesContext.getExternalContext().getRequestMap();
+ Integer recurseLevel = (Integer) requestMap.get(_RECURSE_COUNTER);
+ if(recurseLevel == null)
+ recurseLevel = 0;
+ if(recurseLevel == 0)
+ requestMap.put(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY, this.getId());
+
+ recurseLevel++;
+ requestMap.put(_RECURSE_COUNTER, recurseLevel);
+
// Need to push several items onto the stack now as we recurse
// into another menu model.
@@ -260,6 +283,14 @@
// Now must pop the values cause we are back to the parent
// model.
_restoreModelData();
+
+ recurseLevel = (Integer) requestMap.get(_RECURSE_COUNTER);
+ recurseLevel --;
+ requestMap.put(_RECURSE_COUNTER, recurseLevel);
+
+ if(recurseLevel == 0)
+ requestMap.remove(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY);
+
// Name of the managed bean that is the sub menu XMLMenuModel.
String modelStr = expr.substring(expr.indexOf('{')+1,
@@ -407,11 +438,8 @@
// later NPEs if menu model methods are called.
_LOG.warning ("CREATE_TREE_WARNING: Empty Tree!");
- // Create empty treeModel
- ChildPropertyTreeModel treeModel = new ChildPropertyTreeModel();
-
- // Put it in the map
- _treeModelMap.put(_currentTreeModelMapKey, treeModel);
+ List<MenuNode> list = Collections.emptyList();
+ _menuList = list;
}
else
{
@@ -421,14 +449,8 @@
ChildPropertyTreeModel treeModel =
new ChildPropertyTreeModel(_menuList, "children");
- // Put it in the map
- _treeModelMap.put(_currentTreeModelMapKey, treeModel);
-
- // If Model is the Root, then build Model's hashmaps
- // and set them on the Root Model.
- XMLMenuModel rootModel = getRootModel();
- if (rootModel == getModel())
+ if (_isRootHandler)
{
_viewIdFocusPathMap = new HashMap<String,List<Object>>();
_nodeFocusPathMap = new HashMap<Object, List<Object>>();
@@ -440,13 +462,6 @@
// Populate the maps
_addToMaps(treeModel, _viewIdFocusPathMap, _nodeFocusPathMap, _idNodeMap);
- // Cache the maps. There is a possibility of multiple
- // root models so we must cache the maps on a per root model
- // basis.
- _viewIdFocusPathMapMap.put(_currentTreeModelMapKey, _viewIdFocusPathMap);
- _nodeFocusPathMapMap.put(_currentTreeModelMapKey, _nodeFocusPathMap);
- _idNodeMapMap.put(_currentTreeModelMapKey, _idNodeMap);
-
treeModel.setRowKey(oldPath);
}
}
@@ -459,7 +474,7 @@
*/
public Map<String, List<Object>> getViewIdFocusPathMap(Object modelKey)
{
- return _viewIdFocusPathMapMap.get(modelKey);
+ return _viewIdFocusPathMap;
}
/**
@@ -469,7 +484,7 @@
*/
public Map<Object, List<Object>> getNodeFocusPathMap(Object modelKey)
{
- return _nodeFocusPathMapMap.get(modelKey);
+ return _nodeFocusPathMap;
}
/**
@@ -479,7 +494,7 @@
*/
public Map<String, Object> getIdNodeMap(Object modelKey)
{
- return _idNodeMapMap.get(modelKey);
+ return _idNodeMap;
}
/**
@@ -489,51 +504,53 @@
*/
public TreeModel getTreeModel(String uri)
{
- TreeModel model = _treeModelMap.get(uri);
-
+ List<MenuNode> list = _menuList;
+
// If we have a cached model, return it.
- if (model != null)
- return model;
-
- // Build a Tree model. Parsing puts the tree model
- // in the map, see method endDocument().
- _currentTreeModelMapKey = uri;
+ if (list != null)
+ return new ChildPropertyTreeModel(list,"children");
- try
+ synchronized(this)
{
- // Get a parser. NOTE: we are using the jdk's 1.5 SAXParserFactory
- // and SAXParser here.
- SAXParser parser = _SAX_PARSER_FACTORY.newSAXParser();
-
- // Call the local menu model's getStream() method. This is a model
- // method so that it can be overridden by any model extending
- // XmlMenuModel.
- InputStream inStream = getModel().getStream(uri);
+ list = _menuList;
+ if (list == null)// double check inside lock
+ {
+ // Build a Tree model. Parsing puts the tree model
+ // in the map, see method endDocument().
+ _currentTreeModelMapKey = uri;
+ try
+ {
+ // Get a parser. NOTE: we are using the jdk's 1.5 SAXParserFactory
+ // and SAXParser here.
+ SAXParser parser = _SAX_PARSER_FACTORY.newSAXParser();
+
+ // Call the local menu model's getStream() method. This is a model
+ // method so that it can be overridden by any model extending
+ // XmlMenuModel.
+ InputStream inStream = getModel().getStream(uri);
- // Parse the metadata
- parser.parse(inStream, this);
+ // Parse the metadata
+ parser.parse(inStream, this);
- inStream.close();
- }
- catch (SAXException saxex)
- {
- _LOG.severe ( "SAX Parse Exception parsing " + uri + ": " +
- saxex.getMessage(), saxex);
- }
- catch (IOException ioe)
- {
- _LOG.severe ( "Unable to open an InputStream to " + uri, ioe);
- }
- catch (IllegalArgumentException iae)
- {
- _LOG.severe("InputStream to " + iae + " is null", iae);
- }
- catch (ParserConfigurationException pce)
- {
- _LOG.severe ( "Unable to create SAX parser for " + uri, pce);
+ inStream.close();
+ } catch (SAXException saxex)
+ {
+ _LOG.severe("SAX Parse Exception parsing " + uri + ": " +
+ saxex.getMessage(), saxex);
+ } catch (IOException ioe)
+ {
+ _LOG.severe("Unable to open an InputStream to " + uri, ioe);
+ } catch (IllegalArgumentException iae)
+ {
+ _LOG.severe("InputStream to " + iae + " is null", iae);
+ } catch (ParserConfigurationException pce)
+ {
+ _LOG.severe("Unable to create SAX parser for " + uri, pce);
+ }
+ list = _menuList;
+ }
}
-
- return _treeModelMap.get(uri);
+ return new ChildPropertyTreeModel(list,"children");
}
/**
@@ -549,8 +566,11 @@
Map<String, Object> requestMap =
facesContext.getExternalContext().getRequestMap();
- XMLMenuModel model = (XMLMenuModel) requestMap.get(getRootModelKey());
- return model;
+ Map<String,XMLMenuModel> modelMap = (Map<String,XMLMenuModel>) requestMap.get(getRootModelKey());
+ if(!requestMap.containsKey(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY))
+ return modelMap.get( (this.getId() ) );
+ else
+ return modelMap.get((Integer) requestMap.get(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY));
}
/**
@@ -630,6 +650,31 @@
_currentTreeModelMapKey = uri;
}
+
+ public void setRootHandler(boolean isRoot)
+ {
+ _isRootHandler = isRoot;
+ }
+
+ /**
+ * sets the id of this content handler
+ *
+ * No synchronization necessary,let
+ * the first thread set the id,
+ * the rest of the threads will immediately
+ * see the new value and will not try to
+ * set again.
+ */
+ public void setId(int id)
+ {
+ if(_id == -1)
+ _id = id;
+ }
+
+ public int getId()
+ {
+ return _id;
+ }
//=======================================================================
// Package Private Methods
//=======================================================================
@@ -996,7 +1041,7 @@
//========================================================================
private List<List<MenuNode>> _menuNodes;
- private List<MenuNode> _menuList;
+ private volatile List<MenuNode> _menuList;
private String _currentTreeModelMapKey;
private int _nodeDepth;
private int _skipDepth = -1;
@@ -1006,10 +1051,6 @@
private String _resBundleName;
private Map<String, String> _attrMap;
- private Map<String, TreeModel> _treeModelMap;
- private Map<Object, Map<String, List<Object>>> _viewIdFocusPathMapMap;
- private Map<Object, Map<String, Object>> _idNodeMapMap;
- private Map<Object, Map<Object, List<Object>>> _nodeFocusPathMapMap;
private Stack<Object> _saveDataStack;
private Map<String, List<Object>> _viewIdFocusPathMap;
private Map<Object, List<Object>> _nodeFocusPathMap;
@@ -1021,6 +1062,10 @@
// Root Menu model's Session map key
private String _rootModelKey = null;
+
+ private volatile boolean _isRootHandler;
+
+ private volatile int _id = -1;
// Nodes
private final static String _GROUP_NODE = "groupNode";
@@ -1063,5 +1108,12 @@
private final static TrinidadLogger _LOG =
TrinidadLogger.createTrinidadLogger(MenuContentHandlerImpl.class);
+
+ private static final String _RECURSE_COUNTER =
+ "org.apache.myfaces.trinidadinternal.menu.MenuContentHandlerImpl._RECURSE_COUNTER";
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5330432089846748485L;
} // endclass MenuContentHandlerImpl
Modified: myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java?rev=763596&r1=763595&r2=763596&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java (original)
+++ myfaces/trinidad/branches/1.2.11.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java Thu Apr 9 10:48:00 2009
@@ -573,6 +573,107 @@
_modelId = modelId;
}
+ public int getRootId()
+ {
+ return _rootId;
+ }
+ public void setRootId(int id)
+ {
+ _rootId = id;
+ }
+
+
+ public final String getLabelProperty()
+ {
+ return _label;
+ }
+
+ public final String getIconProperty()
+ {
+ return _icon;
+ }
+
+ public final List<MenuNode> getChildrenProperty()
+ {
+ return _children;
+ }
+
+ public final String getFocusViewIdProperty()
+ {
+ return _focusViewId;
+ }
+
+ public final String getRenderedProperty()
+ {
+ return _renderedStr;
+ }
+
+ public final String getDisabledProperty()
+ {
+ return _disabledStr;
+ }
+
+ public final String getVisibleProperty()
+ {
+ return _visibleStr;
+ }
+
+ public final String getReadOnlyProperty()
+ {
+ return _readOnlyStr;
+ }
+
+ public final String getHandlerIdProperty()
+ {
+ return _handlerId;
+ }
+
+ public final String getBundleKeyProperty()
+ {
+ return _bundleKey;
+ }
+
+ public final String getBundleNameProperty()
+ {
+ return _bundleName;
+ }
+
+ public final String getAccessKeyProperty()
+ {
+ return _accessKey;
+ }
+
+ public final String getIdProperty()
+ {
+ return _id;
+ }
+
+ public final String getModelIdProperty()
+ {
+ return _modelId;
+ }
+
+
+ public final String getLabelAndAccessKeyProperty()
+ {
+ return _labelAndAccessKey;
+ }
+
+ public final String getDefaultFocusPathProperty()
+ {
+ return _defaultFocusPathStr;
+ }
+
+ public final String getRootModelKeyProperty()
+ {
+ return _rootModelKey;
+ }
+
+ public final int getRootIdProperty()
+ {
+ return _rootId;
+ }
+
/**
* setResBundleKey - sets the name of the resource bundle used in
* obtaining the node's label text. Used, along with the handerId,
@@ -655,11 +756,21 @@
Map<String, Object> requestMap =
facesContext.getExternalContext().getRequestMap();
- XMLMenuModel model = (XMLMenuModel) requestMap.get(getRootModelKey());
+ Map map = (Map) requestMap.get(getRootModelKey());
+ XMLMenuModel model = (XMLMenuModel) map.get(getRootId());
return model;
}
/**
+ * Construct a thread safe version
+ * of this object and return it.
+ * @return a thread safe copy of this object.
+ */
+ protected MenuNode getThreadSafeCopy()
+ {
+ return null;
+ }
+ /**
* _joinLabelAndAccessKey - takes a string label and string accessKey
* and combines them into a single labelAndAccessKey string.
*
@@ -778,4 +889,7 @@
// Root Menu model's Request Map Key
private String _rootModelKey = null;
+
+ private int _rootId;
+
}