package com.litestruts;
import com.view.View;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
public class Struts {
@SuppressWarnings("TryWithIdenticalCatches")
private static Document init() {
try {
File file = new File("res/struts.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(file);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static Element findStrutsElement(Document document) {
NodeList nodeList = document.getElementsByTagName("struts");
if (nodeList.getLength() == 0) {
throw new NoSuchElementException("No tag named struts");
}
return (Element) nodeList.item(0);
}
private static Element findElementByName(String actionName) {
Document d = init();
Element element = findStrutsElement(d);
NodeList nodeList = element.getElementsByTagName("action");
if (nodeList.getLength() == 0) {
throw new NoSuchElementException("No tag named action");
}
for (int i = 0; i < nodeList.getLength(); ++i) {
Element e = (Element) nodeList.item(i);
String tmp = e.getAttribute("name");
if (tmp.equals(actionName)) {
return e;
}
}
return null;
}
private static String findClassNameByElement(Element actionElement) {
return actionElement.getAttribute("class");
}
private static Class findClassByName(String actionClassName) {
try {
return Class.forName(actionClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked TryWithIdenticalCatches")
private static Object createActionObject(Class actionClass) {
try {
Constructor actionClassConstructor = actionClass.getConstructor();
return actionClassConstructor.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private static String capitalize(String s) {
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
@SuppressWarnings("unchecked")
private static Method findSetterFromClass(String setterName, Class actionClass) {
try {
Class[] paramTypes = {String.class};
return actionClass.getDeclaredMethod("set" + capitalize(setterName), paramTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("TryWithIdenticalCatches")
private static void invokeSetter(Object o, Method setter, String param) {
try {
setter.invoke(o, param);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private static void invokeSetters(Object o, Class c, Map<String, String> p) {
for (Map.Entry<String, String> pair : p.entrySet()) {
Method setter = findSetterFromClass(pair.getKey(), c);
invokeSetter(o, setter, pair.getValue());
}
}
@SuppressWarnings("unchecked TryWithIdenticalCatches")
private static String invokeExecute(Object o, Class c) {
try {
Method execute = c.getDeclaredMethod("execute");
return (String) execute.invoke(o);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return "";
}
@SuppressWarnings("TryWithIdenticalCatches")
private static String invokeGetter(Object o, Method getter) {
try {
return (String) getter.invoke(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private static Map<String, String> invokeGetters(Object o, Class c) {
Map<String, String> map = new HashMap<>();
for (Method method : c.getDeclaredMethods()) {
String s = method.getName();
if (s.substring(0, 3).equals("get")) {
String dataMember = s.substring(3).toLowerCase();
map.put(dataMember, invokeGetter(o, method));
}
}
return map;
}
private static String findJspByResult(String result, Element actionElement) {
NodeList nodeList = actionElement.getElementsByTagName("result");
for (int i = 0; i < nodeList.getLength(); ++i) {
Element element = (Element) nodeList.item(i);
if (element.getAttribute("name").equals(result)) {
return element.getTextContent();
}
}
return "";
}
public static View runAction(String actionName, Map<String, String> parameters) {
/*
0. 读取配置文件struts.xml
1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象)
据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是
("name"="test" , "password"="1234") ,
那就应该调用 setName和setPassword方法
2. 通过反射调用对象的execute 方法, 并获得返回值,例如"success"
3. 通过反射找到对象的所有getter方法(例如 getMessage),
通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} ,
放到View对象的parameters
4. 根据struts.xml中的 <result> 配置,以及execute的返回值, 确定哪一个jsp,
放到View对象的jsp字段中。
*/
Element actionElement = findElementByName(actionName);
String actionClassName = findClassNameByElement(actionElement);
Class actionClass = findClassByName(actionClassName);
Object actionObject = createActionObject(actionClass);
invokeSetters(actionObject, actionClass, parameters);
String result = invokeExecute(actionObject, actionClass);
Map<String, String> viewParams = invokeGetters(actionObject, actionClass);
View view = new View();
view.setParameters(viewParams);
view.setJsp(findJspByResult(result, actionElement));
return view;
}
}