Java tutorial
/* * Copyright(C) 2010-2012 Alibaba Group Holding Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ package com.taobao.ad.easyschedule.security; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.Resource; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.*; public class ActionSecurityBean implements InitializingBean, ApplicationContextAware { String encoding = "UTF-8"; String[] beanNames = new String[] { "*Action" }; public void setEncoding(String encoding) { this.encoding = encoding; } public void setBeanNames(String[] beanNames) { this.beanNames = beanNames; } private Resource xml; private List<MenuItem> menu; private Map<Long, Module> moduleIndex = new HashMap<Long, Module>(); private Map<Method, Module> methodIndex = new HashMap<Method, Module>(); /** * ?ID?? * * @param id * ?ID * @return */ public Module getModule(Long id) { return moduleIndex.get(id); } /** * ? * * @return Set<Method> */ public Set<Method> getOperationMethodSet() { return Collections.unmodifiableSet(methodIndex.keySet()); } /** * ??(Feature) ID????? * * @param moduleIds * @return */ public List<MenuItem> getMenu(Collection<Long> moduleIds) { if (moduleIds == null || moduleIds.isEmpty()) { return Collections.emptyList(); } Map<Long, Long> ids = new HashMap<Long, Long>(); for (Long id : moduleIds) { ids.put(id, null); } List<MenuItem> subtree = new LinkedList<MenuItem>(); List<MenuItem> menu = this.getMenu(); for (MenuItem item : menu) { if (item.getItems() != null) { List<MenuItem> submenu = new LinkedList<MenuItem>(); for (MenuItem subitem : item.getItems()) { boolean add = false; MenuItem newItem = new MenuItem(subitem.getName(), subitem.getLink(), subitem.getTarget()); if (subitem.getModules() != null && subitem.state == 0) { for (Module module : subitem.getModules()) { if (ids.containsKey(module.getId())) { add = true; newItem.addModule(module); } } } else if (subitem.state == 1 || subitem.getModules() == null) { add = true; } if (add) { submenu.add(newItem); } } if (!submenu.isEmpty()) { MenuItem newItem = new MenuItem(item.getName()); newItem.addSubItems(submenu); subtree.add(newItem); } } } return subtree; } /** * ?Module???? * * @return List<MenuItem> */ public boolean hasAccess(Collection<Integer> moduleIds, Method method) { if (!methodIndex.containsKey(method)) { return true; } if (moduleIds == null) { return false; } Module module = methodIndex.get(method); for (Integer id : moduleIds) { if (id.intValue() == module.getId()) { return true; } } return false; } public void setXml(Resource resource) { if (resource == null) { throw new IllegalArgumentException("Can't load menu configration file"); } this.xml = resource; this.getMenu(); } private long lastModified = 0; private Object lock = new Object(); /** * ??? * * @throws Exception */ public List<MenuItem> getMenu() { synchronized (lock) { long thisModified; try { thisModified = xml.getFile().lastModified(); } catch (IOException e) { throw new IllegalArgumentException("Can't find menu configration file"); } if (lastModified == thisModified) { return menu; } // System.out.println("load new menu."); lastModified = thisModified; try { menu = Collections.unmodifiableList(readMenuFromFile()); return menu; } catch (Exception e) { // ??????? System.out.println("load new menu fail,use old menu config."); return menu; } } } /** * ??? * * @return * @throws Exception */ private List<MenuItem> readMenuFromFile() throws Exception { List<MenuItem> tmpMenu; Map<Long, Module> tmpModuleIndex; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document dom = db.parse(new InputSource(new InputStreamReader(xml.getInputStream(), encoding))); NodeList items = dom.getElementsByTagName("item"); tmpMenu = new LinkedList<MenuItem>(); tmpModuleIndex = new HashMap<Long, Module>(); MenuItem currentTopMenu = null; for (int i = 0; i < items.getLength(); i++) { Node item = items.item(i); String name = item.getAttributes().getNamedItem("name").getNodeValue(); String link = "#"; if (item.getAttributes().getNamedItem("link") != null) link = item.getAttributes().getNamedItem("link").getNodeValue(); Node parent = item.getParentNode(); if ("menu".equals(parent.getNodeName())) { currentTopMenu = new MenuItem(name, link); tmpMenu.add(currentTopMenu); } else if ("item".equals(parent.getNodeName())) { MenuItem subMenu = new MenuItem(name); currentTopMenu.addSubItem(subMenu); // add the sub node to // parent node if (item.getAttributes().getNamedItem("link") != null) subMenu.link = item.getAttributes().getNamedItem("link").getNodeValue(); if (item.getAttributes().getNamedItem("target") != null) subMenu.target = item.getAttributes().getNamedItem("target").getNodeValue(); if (item.getAttributes().getNamedItem("state") != null) { if ("show".equalsIgnoreCase(item.getAttributes().getNamedItem("state").getNodeValue())) { subMenu.state = 1; } else if ("hide" .equalsIgnoreCase(item.getAttributes().getNamedItem("state").getNodeValue())) { subMenu.state = -1; } } setModules(subMenu, item, tmpModuleIndex); } } } catch (Exception e) { throw e; } this.moduleIndex = tmpModuleIndex; return tmpMenu; } private void setModules(MenuItem menuItem, Node item, Map<Long, Module> tmpModuleIndex) { NodeList children = item.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if ("module".equals(node.getNodeName())) { // System.out.println(" "+node.getAttributes().getNamedItem("id")); menuItem.addModule( new Module(Long.parseLong(node.getAttributes().getNamedItem("id").getNodeValue()), node.getAttributes().getNamedItem("name").getNodeValue(), tmpModuleIndex)); } } } /** * ?Spring?bean??? ??BO? * * @throws Exception */ public void afterPropertiesSet() throws Exception { } /** * ??BO?Annotation??Annotation? */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { String[] beanNames = applicationContext.getBeanDefinitionNames(); if (beanNames == null || beanNames.length == 0) { System.err.println( "Warning: seems there are no Spring Beans defined, please double check.................."); return; } for (String name : beanNames) { if (!name.endsWith("Action")) { continue; } Class<?> c = AopUtils.getTargetClass(applicationContext.getBean(name)); Object bean = applicationContext.getBean(name); while (Proxy.isProxyClass(c) && (bean instanceof Advised)) { try { bean = ((Advised) bean).getTargetSource(); bean = ((TargetSource) bean).getTarget(); c = bean.getClass(); } catch (Exception e) { throw new IllegalStateException("Can't initialize SecurityBean, due to:" + e.getMessage()); } } long moduleIdDefinedInInterface = -1; ActionSecurity moduleAnno = AnnotationUtils.findAnnotation(c, ActionSecurity.class); if (moduleAnno != null) { moduleIdDefinedInInterface = moduleAnno.module(); } Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { ActionSecurity methodAnno = AnnotationUtils.findAnnotation(method, ActionSecurity.class); if (methodAnno != null || moduleIdDefinedInInterface != -1) { if (methodAnno == null) { methodAnno = moduleAnno; // use interface annotation } long module = methodAnno.module() == 0 ? moduleIdDefinedInInterface : methodAnno.module(); Module myModule = moduleIndex.get(module); if (myModule == null) { throw new IllegalArgumentException( "Found invalid module id:" + module + " in method annotation:" + method + " valid module ids are: " + moduleIndex.keySet()); } if (methodAnno.enable()) { myModule.addOperation(method, methodAnno, methodIndex); } } } } System.out.println("[ActionSecurityBean] Total " + methodIndex.size() + " methods are secured!"); } public class MenuItem { String name; String link; String target; short state = 0; List<MenuItem> items; List<Module> modules; public String getTarget() { return target; } public void setTarget(String target) { this.target = target; } public void addSubItem(MenuItem item) { if (items == null) { items = new LinkedList<MenuItem>(); } items.add(item); } public void addSubItems(List<MenuItem> addItems) { if (items == null) { items = new ArrayList<MenuItem>(addItems.size()); } items.addAll(addItems); } public MenuItem(String name, String link) { this.name = name; this.link = link; } public MenuItem(String name, String link, String target) { this.name = name; this.link = link; this.target = target; } public void addModule(Module module) { if (modules == null) { modules = new LinkedList<Module>(); } modules.add(module); } public MenuItem(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public List<MenuItem> getItems() { return items; } public void setItems(List<MenuItem> items) { this.items = items; } public List<Module> getModules() { return modules; } public void setModules(List<Module> modules) { this.modules = modules; } public boolean isTopMenu() { return items != null && !items.isEmpty(); } @Override public String toString() { if (isTopMenu()) { return "menu: " + name + "\n\t\tsub menu:" + items + "\n"; } else { return name + " " + link + "\n\t\t\t\tmodules:" + modules + "\n"; } } } /** * ????? */ public class Module { long id; String name; Map<Method, ActionSecurity> operations; public Module(long id, String name, Map<Long, Module> moduleIndex) { if (moduleIndex.containsKey(id)) { // System.out.println(">>>"+id); throw new IllegalArgumentException("Found duplicate module id:" + id); } this.id = id; this.name = name; moduleIndex.put(id, this); } public long getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addOperation(Method m, ActionSecurity s, Map<Method, Module> methodIndex) { if (!s.enable()) { return; } if (operations == null) { operations = new HashMap<Method, ActionSecurity>(); } methodIndex.put(m, this); operations.put(m, s); } @Override public String toString() { return "id:" + id + " " + name + "\n\t\t\t\t methods:" + operations + "\n"; } } }