package litestruts;
import datastructure.basic.ArrayList;
import litestruts.exception.XmlElementNotFoundException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;
public class Struts {
/*
0. 读取配置文件struts.xml
1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象)
据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是
("name"="test" , "password"="1234") ,
那就应该调用 setName和setPassword方法
2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success"
3. 通过反射找到对象的所有getter方法(例如 getMessage),
通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} ,
放到View对象的parameters
4. 根据struts.xml中的 <result> 配置,以及execute的返回值, 确定哪一个jsp,
放到View对象的jsp字段中。
*/
public static View runAction(String actionName, Map<String,String> parameters) {
//读取xml
Document document;
try {
document = loadXml();
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
return null;
}
//获取所有action
Element struts = document.getDocumentElement();
NodeList actionList = struts.getElementsByTagName("action");
//根据actionName找到相应action,创建View
try {
Element action = getAction(actionList, actionName);
return createView(action, parameters);
} catch (InvocationTargetException | XmlElementNotFoundException e) {
e.printStackTrace();
return null;
}
}
private static Element getAction(NodeList actionList, String name) throws XmlElementNotFoundException {
//根据actionName找到相应action
for (int i = 0; i < actionList.getLength(); ++i) {
Element action = (Element) actionList.item(i);
if (action.getAttribute("name").equals(name)) {
return action;
}
}
throw new XmlElementNotFoundException(elementNotFoundMessage("action", name));
}
private static View createView(Element action, Map<String, String> parameters)
throws InvocationTargetException {
String className = action.getAttribute("class");
Class clazz;
Object object;
String executeResult;
try {
clazz = Class.forName(className);
object = clazz.newInstance();
setParameters(object, parameters);
executeResult = execute(object);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return null;
}
NodeList resultList = action.getElementsByTagName("result");
String jsp;
Map<String, String> parameterMap;
try {
jsp = getJsp(resultList, executeResult);
parameterMap = createParameterMap(clazz, object);
} catch (XmlElementNotFoundException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
View view = new View();
view.setJsp(jsp);
view.setParameters(parameterMap);
return view;
}
private static Map<String, String> createParameterMap(Class clazz, Object object)
throws InvocationTargetException, IllegalAccessException {
//获取所有getter
Method[] getters = getAllGetters(clazz);
//创建parameter Map
Map<String, String> parameterMap = new Hashtable<>();
for (Method getter : getters) {
parameterMap.put(getAttributeName(getter.getName()), (String) getter.invoke(object));
}
return parameterMap;
}
private static String getJsp(NodeList resultList, String executeResult) throws XmlElementNotFoundException {
return getResult(resultList, executeResult).getTextContent();
}
private static Element getResult(NodeList resultList, String name) throws XmlElementNotFoundException {
for (int j = 0; j < resultList.getLength(); ++j) {
Element result = (Element) resultList.item(j);
if (result.getAttribute("name").equals(name)) {
return result;
}
}
throw new XmlElementNotFoundException(elementNotFoundMessage("result", name));
}
private static String elementNotFoundMessage(String elementName, String nameAttribute) {
return "\"" + elementName + "\" XML element not found: " + "attribute \"name\": " + nameAttribute;
}
private static Method[] getAllGetters(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
ArrayList list = new ArrayList();
for (Method method : methods) {
if (method.getName().startsWith("get")) {
list.add(method);
}
}
Method[] getters = new Method[list.size()];
for (int i = 0; i < list.size(); ++i) {
getters[i] = (Method) list.get(i);
}
return getters;
}
private static Document loadXml() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
Document document;
builder = factory.newDocumentBuilder();
document = builder.parse(new File("src/litestruts/struts.xml"));
return document;
}
private static String execute(Object object)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method execute = object.getClass().getDeclaredMethod("execute");
return (String) execute.invoke(object);
}
private static void setParameters(Object object, Map<String, String> parameters)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
for (Map.Entry<String, String> entry : parameters.entrySet()) {
Method setter = object.getClass().getDeclaredMethod(getSetterName(entry.getKey()), String.class);
if (setter != null) {
setter.invoke(object, entry.getValue());
}
}
}
private static String getSetterName(String attributeName) {
return "set" + Character.toUpperCase(attributeName.charAt(0)) + attributeName.substring(1);
}
private static String getAttributeName(String getterOrSetterName) {
String sub = getterOrSetterName.substring(3);
return Character.toLowerCase(sub.charAt(0)) + sub.substring(1);
}
}