/******************************************************************************* * ***** BEGIN LICENSE BLOCK Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is the OpenCustomer CRM. * * The Initial Developer of the Original Code is Thomas Bader (Bader & Jene * Software-Ingenieurb�ro). Portions created by the Initial Developer are * Copyright (C) 2006 the Initial Developer. All Rights Reserved. * * Contributor(s): Thomas Bader <thomas.bader@bader-jene.de> * * ***** END LICENSE BLOCK ***** */ package org.opencustomer.webapp.util.menu; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.log4j.Logger; import org.apache.struts.config.ActionConfig; import org.apache.struts.config.ModuleConfig; import org.opencustomer.webapp.auth.Authenticator; import org.opencustomer.webapp.auth.Right; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class MenuFactory { private final static Logger log = Logger.getLogger(MenuFactory.class); private Menu menu; private ModuleConfig moduleConfig; public MenuFactory(ModuleConfig moduleConfig) throws MenuFactoryException { this.moduleConfig = moduleConfig; InputStream in = null; try { in = this.getClass().getClassLoader().getResourceAsStream("org/opencustomer/webapp/util/menu/menu.xml"); initMenu(in); } finally { if(in != null) { try { in.close(); } catch(IOException e) { log.error("could not close stream", e); } } } } private MenuFactory(ModuleConfig moduleConfig, InputStream in) throws MenuFactoryException { this.moduleConfig = moduleConfig; initMenu(in); } private MenuFactory(ModuleConfig moduleConfig, File confFile) throws FileNotFoundException, MenuFactoryException { this.moduleConfig = moduleConfig; FileInputStream in = null; try { in = new FileInputStream(confFile); initMenu(in); } finally { if(in != null) { try { in.close(); } catch(IOException e) { log.error("could not close stream", e); } } } } private void initMenu(InputStream in) throws MenuFactoryException { if(log.isDebugEnabled()) log.debug("init menu"); menu = load(in); debugMenu(menu); } private static void debugMenu(Menu menu) { if(log.isDebugEnabled()) { for(MenuItem item : menu.getItems()) { log.debug(item); for(MenuItem subItem : item.getChildItems()) { log.debug(" "+subItem); for(MenuItem subItem2 : subItem.getChildItems()) { log.debug(" "+subItem2); } } } } } public Menu getCustomizedMenu(Authenticator auth) { if(log.isDebugEnabled()) log.debug("customize menu"); Menu customizedMenu = (Menu)menu.clone(); if(auth != null) customize(customizedMenu.getItems(), auth); customizedMenu.initialize(); debugMenu(customizedMenu); return customizedMenu; } private static void customize(List<MenuItem> items, Authenticator auth) { Iterator<MenuItem> itemsIt = items.iterator(); while(itemsIt.hasNext()) { MenuItem item = itemsIt.next(); customize(item.getChildItems(), auth); if (item.getChildItems().isEmpty()) { if (!auth.isValid(item.getRights())) { if (log.isDebugEnabled()) log.debug("remove item with invalid rights: " + item); itemsIt.remove(); } } } } private Menu load(InputStream in) throws MenuFactoryException { if(log.isDebugEnabled()) log.debug("load menu from xml"); Menu menu = new Menu(); try { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.parse(in); Node root = document.getDocumentElement(); if("menu".equals(root.getNodeName())) { NodeList nodes = root.getChildNodes(); for(int i=0; i<nodes.getLength(); i++) { if(nodes.item(i).getNodeType() == Node.ELEMENT_NODE) { menu.getItems().add(loadMenuItem(nodes.item(i), null)); } } } else { throw new MenuFactoryException("invalid attribute found: '"+root.getNodeName()+"' (need: 'menu')"); } } catch(Exception e) { throw new MenuFactoryException("could not load menu", e); } return menu; } private MenuItem loadMenuItem(Node node, MenuItem parentItem) throws MenuFactoryException { MenuItem item = null; if("menuitem".equals(node.getNodeName())) { item = new MenuItem(); item.setParentItem(parentItem); NamedNodeMap attributes = node.getAttributes(); for(int i=0; i<attributes.getLength(); i++) { Node attributeNode = attributes.item(i); if(attributeNode.getNodeType() == Node.ATTRIBUTE_NODE) { String name = attributeNode.getNodeName(); if("action".equals(name)) { item.setAction(attributeNode.getNodeValue()); if(moduleConfig != null) { ActionConfig config = moduleConfig.findActionConfig(item.getAction()); item.setRights(toRightArray(config.getRoleNames())); } } else if("imageKey".equals(name)) { item.setImageKey(attributeNode.getNodeValue()); } else if("altKey".equals(name)) { item.setAltKey(attributeNode.getNodeValue()); } else if("messageKey".equals(name)) { item.setMessageKey(attributeNode.getNodeValue()); } else if("titleKey".equals(name)) { item.setTitleKey(attributeNode.getNodeValue()); } else { throw new MenuFactoryException("invalid attribute found: '"+attributeNode.getNodeName()+"'"); } } } NodeList nodes = node.getChildNodes(); for(int i=0; i<nodes.getLength(); i++) { if(nodes.item(i).getNodeType() == Node.ELEMENT_NODE) { item.getChildItems().add(loadMenuItem(nodes.item(i), item)); } } if((item.getImageKey() != null && item.getAltKey() == null) || (item.getImageKey() == null && item.getAltKey() != null)) { throw new MenuFactoryException("attributes 'imageKey' and 'altKey' have to be used together"); } else if(item.getAction() == null && item.getChildItems().isEmpty()) { throw new MenuFactoryException("attribute 'action' have to be set for leaf nodes"); } else if(item.getAction() != null && !item.getChildItems().isEmpty()) { throw new MenuFactoryException("attribute 'action' have not to be set for non leaf nodes"); } } else { throw new MenuFactoryException("invalid node found: '"+node.getNodeName()+"' (need: 'menuitem')"); } return item; } private static Right[] toRightArray(String[] roles) throws MenuFactoryException { List<Right> rights = new ArrayList<Right>(); for (int i = 0; i < roles.length; i++) { try { rights.add(Right.parseRight(roles[i])); } catch (IllegalArgumentException e) { throw new MenuFactoryException("invalid right found in module config: '"+roles[i]+"'", e); } } return rights.toArray(new Right[rights.size()]); } }