/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed 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.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.framework.components.mifosmenu;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang.StringUtils;
import org.mifos.config.business.MifosConfigurationManager;
import org.mifos.core.MifosResourceUtil;
import org.mifos.framework.exceptions.MenuParseException;
import org.mifos.framework.exceptions.SystemException;
import org.mifos.framework.util.helpers.FilePaths;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* It parses xml, builds and return crude menu for application
*/
public class MenuParser {
/**
* Method to parse xml and return crude menu
*
* @return array of crude Menu objects
*/
public static Menu[] parse() throws SystemException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
SchemaFactory schfactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schfactory.setErrorHandler(null);
Schema schema = schfactory.newSchema(new StreamSource(MifosResourceUtil.getClassPathResourceAsStream(FilePaths.MENUSCHEMA)));
factory.setNamespaceAware(false);
factory.setValidating(false);
factory.setSchema(schema);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(MifosResourceUtil.getClassPathResourceAsStream(FilePaths.MENUPATH));
NodeList tabNodeList = document.getElementsByTagName(MenuConstants.TOPMENUTAB);
Menu leftMenus[] = new Menu[tabNodeList.getLength()];
for (int i = 0; i < tabNodeList.getLength(); i++) {
leftMenus[i] = new Menu();
leftMenus[i].setTopMenuTabName(((Element) tabNodeList.item(i)).getAttribute(MenuConstants.NAME));
leftMenus[i].setMenuGroups(createMenuGroup(tabNodeList.item(i)));
String menuHeading = ((Element) tabNodeList.item(i)).getElementsByTagName(MenuConstants.LEFTMENULABEL)
.item(0).getFirstChild().getTextContent().trim();
leftMenus[i].setMenuHeading(menuHeading);
}
return leftMenus;
} catch (SAXParseException spe) {
throw new MenuParseException(spe);
} catch (SAXException sxe) {
throw new MenuParseException(sxe);
} catch (ParserConfigurationException pce) {
throw new MenuParseException(pce);
} catch (IOException ioe) {
throw new MenuParseException(ioe);
}
}
/**
* Method to build crude MenuGroup objects for a given top-menu-tab
*
* @param leftMenu
* is the root node for a top-menu-tab
* @return array of MenuGroup objects
*/
static MenuGroup[] createMenuGroup(Node leftMenu) throws SystemException {
NodeList menuGpNodeList = ((Element) leftMenu).getElementsByTagName(MenuConstants.MENUGROUP);
MenuGroup menuGroup[] = new MenuGroup[menuGpNodeList.getLength()];
for (int i = 0; i < menuGpNodeList.getLength(); i++) {
menuGroup[i] = new MenuGroup();
menuGroup[i].setMenuItems(createMenuItems(menuGpNodeList.item(i)));
menuGroup[i].setDisplayName(getDisplayName((Element) menuGpNodeList.item(i)));
}
return menuGroup;
}
/**
* Method to build crude MenuItem objects for a MenuGroup
*
* @param menuGroup
* is the root node for MenuGroup.
* @return array of MenuItem objects
*/
static MenuItem[] createMenuItems(Node menuGroup) throws SystemException {
NodeList menuItemNodeList = ((Element) menuGroup).getElementsByTagName(MenuConstants.MENUITEM);
MenuItem menuItem[] = new MenuItem[menuItemNodeList.getLength()];
int hiddenItems = 0;
for (int i = 0, j = 0; i < menuItemNodeList.getLength(); i++) {
if (isMenuItemVisible((Element) menuItemNodeList.item(i))) {
menuItem[j] = new MenuItem();
menuItem[j].setDisplayName(getDisplayName((Element) menuItemNodeList.item(i)));
menuItem[j].setLinkValue(getLinkValue((Element) menuItemNodeList.item(i)));
j++;
} else {
hiddenItems++;
}
}
if (hiddenItems > 0) {
menuItem = removeEmptyMenuItems(menuItem, hiddenItems);
}
return menuItem;
}
private static MenuItem[] removeEmptyMenuItems(MenuItem menuItems[], int hiddenItems) {
MenuItem newMenuItems[] = new MenuItem[menuItems.length - hiddenItems];
for (int i = 0, j = 0; i < menuItems.length; i++) {
if (menuItems[i] != null) {
newMenuItems[j++] = menuItems[i];
}
}
return newMenuItems;
}
/**
* Uses boolean keys in the application-wide configuration to determine if
* menu items should be displayed. Missing keys will cause
* {@link java.util.NoSuchElementException} to be thrown. Keys are
* configured in menu.xml.
*/
private static boolean isMenuItemVisible(Element element) {
String visiKey = element.getAttribute(MenuConstants.KEY_FOR_HIDDEN);
if (StringUtils.isNotBlank(visiKey)) {
MifosConfigurationManager cm = MifosConfigurationManager.getInstance();
return cm.getBoolean(visiKey);
}
// if attribute doesn't exist, a configuration key wasn't specified,
// so menu item must be visible
return true;
}
/**
* Method to get all keys for a displayname of a given node
*
* @param node
* is the element whose display name is to be obtained
* @return array of keys respective to display name
*/
static String[] getDisplayName(Element node) {
NodeList displaynameNodeList = node.getElementsByTagName(MenuConstants.DISPLAYNAME);
NodeList nameNodeList = ((Element) displaynameNodeList.item(0))
.getElementsByTagName(MenuConstants.NAMEFRAGMENT);
String displayNameStr[] = new String[nameNodeList.getLength()];
for (int i = 0; i < nameNodeList.getLength(); i++) {
displayNameStr[i] = nameNodeList.item(i).getFirstChild().getTextContent().trim();
}
return displayNameStr;
}
/**
* Method to get link value for a menu item
*
* @param node
* is the menu item whose link is to be obtained
* @return link as string
*/
static String getLinkValue(Element node) {
return node.getElementsByTagName(MenuConstants.LINKVALUE).item(0).getFirstChild().getTextContent().trim();
}
}