Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.trinidad.model;
import java.io.InputStream;
import java.io.Serializable;
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;
import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
import org.apache.myfaces.trinidad.util.ContainerUtils;
import org.apache.myfaces.trinidad.util.TransientHolder;
/**
* Creates a Menu Model from a TreeModel where nodes in the treeModel
* contain viewId information.
*
* Each node must have either a bean getter method or a Map property
* that returns a viewId. There are several restrictions on the data:
*
* o The nodes in the tree must either be all beans or all maps,
* but not a mix of beans and maps.
* o The viewId of a node can be null, but if set it must be unique.
* o The tree cannot be mutable.
*
*
* The getFocusRowKey method
*
* o gets the current viewId by calling
* FacesContext.getCurrentInstance().getViewRoot().getViewId()
* o compares the current viewId with the viewId's in the viewIdFocusPathMap
* that was built by traversing the tree when the model was created.
* o returns the focus path to the node with the current viewId or null if the
* current viewId can't be found.
* o in the case where a viewId has multiple focus paths, the currently
* selected node is used as a key into the nodeFocusPathMap to return the
* correct focus path.
*
*
* The Model is created by specifying it in the faces-config.xml file
* as follows
*
*
* Objects of this class are not thread safe and should be used
* only in request scope.
*
*/
/*
* Three hashmaps are also created in order to be able to resolve cases where
* multiple menu items cause navigation to the same viewId. All 3 of these maps
* are created after the metadata is parsed and the tree is built, in the
* MenuContentHandlerImpl.
*
* o The first hashMap is called the viewIdFocusPathMap and is built by
* traversing the tree when the model is created. Each node's focusViewId is
* obtained and used as the key to an entry in the viewIdHashMap. An ArrayList
* is used as the entry's value and each item in the ArrayList is a node's
* rowkey from the tree. This allows us to have duplicate rowkeys for a single
* focusViewId which translates to a menu that contains multiple items pointing
* to the same page. In general, each entry will have an ArrayList of rowkeys
* with only 1 rowkey, AKA focus path.
* o The second hashMap is called the nodeFocusPathMap and is built at the
* same time the viewIdHashMap is built. Each entry's key is the actual node and
* the value is the row key. Since the model keeps track of the currently
* selected menu node, this hashmap can be used to resolve viewId's with
* multiple focus paths. Since we have the currently selected node, we just
* use this hashMap to get its focus path.
* o The third hashMap is called idNodeMap and is built at the same time as the
* previous maps. This map is populated by having each entry contain the node's
* id as the key and the actual node as the value. In order to keep track of
* the currently selected node in the case of a GET, the node's id is appended
* to the request URL as a parameter. The currently selected node's id is
* picked up and this map is used to get the actual node that is currently
* selected.
*
* Keeping track of the currently selected menu item/node.
*
* If an itemNode in the metadata uses its "action" attribute, a POST is done
* and the node's "doAction" method is called when the menu item is clicked. At
* that time, the model is notified through its setCurrentlyPostedNode() method,
* where the current node is set and the request method is set to POST.
*
* If an itemNode in the metadata uses its "destination" attribute, a GET is
* done. Nothing is called on the model when the menu item is clicked. However
* at the time the page is rendered the "getDestination" method for all nodes
* using the "destination" attribute is called. At this point
* we append the node's id to the value of the destination attribute URL, as
* a parameter, and return it. So when getFocusRowKey() is called, we get the
* request the node's parameter matching the currently selected node's id.
* Using the node id, we find the matching node in the idNodeMap and voila, we
* have the currently selected node!
*/
public class XMLMenuModel extends BaseMenuModel
{
public XMLMenuModel()
{
super();
_modelId = Integer.valueOf(System.identityHashCode(this)).toString();
}
/**
* This needs to be overriden by classes extending XmlMenuModel and using APIs for the nodes
* of XmlMenuModel. Default value returned is true for backward compatibilty. The models using
* the external APIs for their nodes must return false.
* @return boolean
*/
protected boolean isCompatibilityMode()
{
return true;
}
/**
* setSource - specifies the XML metadata and creates
* the XML Menu Model.
*
* @param menuMetadataUri - String URI to the XML metadata.
*/
public void setSource(String menuMetadataUri)
{
if (menuMetadataUri == null || "".equals(menuMetadataUri))
return;
_mdSource = menuMetadataUri;
_createModel();
}
/**
* Makes the TreeModel part of the menu model. Also creates the
* _viewIdFocusPathMap, _nodeFocusPathMap, and idNodeMaps.
*
* @param data The Tree Model instance
*/
@Override
public void setWrappedData(Object data)
{
super.setWrappedData(data);
// The only thing the child menu models are needed for are their
// menuLists, which get incorporated into the Root Model's tree.
// 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 (_isRoot)
{
_viewIdFocusPathMap = _contentHandler.getViewIdFocusPathMap(_mdSource);
_nodeFocusPathMap = _contentHandler.getNodeFocusPathMap(_mdSource);
_idNodeMap = _contentHandler.getIdNodeMap(_mdSource);
}
}
/**
* Returns the rowKey to the current viewId, or in the case of where the
* model has nodes with duplicate viewId's and one is encountered, we
* return the rowKey of the currently selected node.
*
*
* The getFocusRowKey method
*
*
gets the current viewId by calling
* FacesContext.getCurrentInstance().getViewRoot().getViewId()
*
compares the current viewId with the viewId's in the viewIdFocusPathMap
* that was built by traversing the tree when the model was created.
*
returns the focus path to the node with the current viewId or null if
* the current viewId can't be found.
*
in the case where a viewId has multiple focus paths, the currently
* selected node is used as a key into the nodeFocusPathMap to return the
* correct focus path.
*
*
* @return the rowKey to the node with the current viewId or null if the
* current viewId can't be found.
*/
@SuppressWarnings("unchecked")
@Override
public Object getFocusRowKey()
{
Object focusPath = null;
String currentViewId = _getCurrentViewId();
FacesContext context = FacesContext.getCurrentInstance();
// getFocusRowKey() is called multiple times during the Process Validations
// Phase and again during the Render Response Phase during each Request.
// During each phase, as described below, the same viewId is passed in. To
// prevent unnecessary looking up of the focus path each time, the previous
// focus path is returned after the first call in each phase, as described
// below.
//
// ** Process Validations Phase:
// During the Process Validations Phase, the prevViewId is initially
// null (gets set to this at the start of each Request). The first time
// getFocusRowKey is called, the currentViewId is that of the node we are
// navigating "from" during the Request. This is stored in prevViewId.
// Because the currentViewId is not equal to the prevViewId,
// the node is looked up, its focus path stored in prevFocusPath, and the
// focus path is returned. On subsequent calls during the Process
// Validations Phase, the currentViewId is always that of the "from" node,
// the currentViewId is equal to the prevViewId, and so we simply
// return prevFocusPath.
//
// ** Render Response Phase:
// During the Render Response Phase, the prevViewId is initially
// that of the "from" node. The first time getFocusRowKey is called
// the currentViewId is that of the node we are navigating "to" during
// the Request. This is stored in prevViewId.
// Because the currentViewId is not equal to the prevViewId,
// the node is looked up, its focus path stored in prevFocusPath, and the
// focus path is returned. On subsequent calls during the Render
// Response Phase, the currentViewId is always that of the "to" node,
// the currentViewId is equal to the prevViewId, and so we simply
// return prevFocusPath.
//
// IMPORTANT: Code that returns the correct focus path for duplicate nodes
// in the node tree actually depends on this optimization.
//
if ((_prevViewId != null) && _prevViewId.equals(currentViewId))
return _prevFocusPath;
// Initializations
_prevViewId = currentViewId;
// How did we get to this page?
// 1) Clicked on a menu item with its action attribute set. This does
// a POST.
// 2) Clicked on a menu item with its destination attribute set. This
// does a GET.
// 3) Navigation to a viewId within our model but done from outside the
// model. Examples, button, text link, etc.
//
// Case 1: POST method. Current Node has already been set and so has the
// request method. The doAction() method of the clicked node calls
// the setCurrentlyPostedNode() method of this model, which sets both. So
// we have nothing to do in this case.
if (_getRequestMethod() != _METHOD_POST)
{
// Case 2: GET method. We have hung the selected node's id off the
// request's URL, which enables us to get the selected node and also
// to know that the request method is GET.
Map paramMap =
context.getExternalContext().getRequestParameterMap();
String UrlNodeId = paramMap.get(_NODE_ID_PROPERTY);
if (UrlNodeId != null)
{
_setCurrentlySelectedNode(_getNodeFromURLParams(UrlNodeId));
_setRequestMethod(_METHOD_GET);
}
}
// Case 3: Navigation to a page within the model from an outside
// method, e.g. button, link text, etc. In this case we set the
// currently selected node to null. This tells us to get the 0th
// element of the ArrayList returned from the viewId hashMap. This
// should be a focus path match to the node whose "defaultFocusPath"
// attribute was set to 'true'.
if (_getRequestMethod() == _METHOD_NONE)
{
_setCurrentlySelectedNode(null);
}
// Get the matching focus path ArrayList for the currentViewId.
// This is an ArrayList because our map allows nodes with the same
// viewId, that is, different focus paths to the same viewId.
ArrayList