package com.bao.lc.site.s3.commands; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.chain.Context; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.filters.AndFilter; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.filters.OrFilter; import org.htmlparser.tags.FormTag; import org.htmlparser.tags.ScriptTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import com.bao.lc.AppConfig; import com.bao.lc.ResMgr; import com.bao.lc.bean.IDValuePair; import com.bao.lc.bean.ResultCode; import com.bao.lc.client.utils.HttpClientUtils; import com.bao.lc.common.ScriptCodeFilter; import com.bao.lc.common.URI2NameBuilder; import com.bao.lc.httpcommand.BasicHttpCommand; import com.bao.lc.httpcommand.params.HttpCommandParams; import com.bao.lc.site.s3.params.TdPNames; import com.bao.lc.site.s3.params.TdParams; import com.bao.lc.util.MiscUtils; public class ConfirmOrder extends BasicHttpCommand { private static Log log = LogFactory.getLog(ConfirmOrder.class); private static final String JS_SUCCESS_REGEX = "var requiredNum=(\\d+?);(\\s+?)var successTicketNum=(\\d+?);"; private static final String JS_ERROR_MSG_REGEX = "var\\s+message\\s+=\\s+\"(.+?)\""; private boolean isConfirmPassengerFormExist = false; protected IDValuePair preExecute(Context context) throws Exception { isConfirmPassengerFormExist = false; return super.preExecute(context); } protected IDValuePair postExecute(Context context) throws Exception { // 1. Save the response content HttpResponse rsp = HttpCommandParams.getResponse(context); String charset = HttpCommandParams.getCharset(rsp, context); URI2NameBuilder ub = new URI2NameBuilder(); ub.uri(HttpCommandParams.getTargetRequestURI(context)); ub.addParamName("method").encoding(charset); String content = HttpClientUtils.saveToString(rsp.getEntity(), charset, ub); context.put(TdPNames._CONFIRM_PASSENGER_CONTENT, content); context.put(TdPNames._CONFIRM_PASSENGER_ENCODING, charset); IDValuePair rc = parseResult(context, content, charset); return rc; } private IDValuePair parseResult(Context context, String content, String charset) throws ParserException { if(isSuccess(context, content, charset)) { TdParams.getUI(context).info(ResMgr.getString("td.msg.ticket.book.ok")); return ResultCode.RC_OK; } IDValuePair rc = parseFailReason(context, content, charset); log.info("Book tickets result: " + rc); return rc; } private boolean isSuccess(Context context, String pageContent, String charset) throws ParserException { boolean ret = false; do { if(!isSuccessByJS(context, pageContent, charset)) { log.info("isSuccessByJS failed"); break; } if(!isSuccessByForm(context, pageContent, charset)) { log.info("isSuccessByForm failed"); break; } ret = true; } while(false); return ret; } private boolean isSuccessByJS(Context context, String pageContent, String charset) throws ParserException { Parser parser = MiscUtils.createParser(pageContent, charset, log); int flags = Pattern.MULTILINE | Pattern.DOTALL; NodeFilter scriptFilter = new ScriptCodeFilter(JS_SUCCESS_REGEX, flags); // parse NodeList nodeList = parser.parse(scriptFilter); if(nodeList.size() < 1) { log.info("Can't find the 'successTicketNum' script. Assume confirm order failed."); return false; } ScriptTag js = (ScriptTag) nodeList.elementAt(0); List<String> valueList = new ArrayList<String>(); int matchCount = MiscUtils.getRegexValue(js.getScriptCode().trim(), JS_SUCCESS_REGEX, valueList, true, flags); if(matchCount != 1) { log.fatal("isSuccessByJS Unexpected: matchCount=" + matchCount); return false; } String requiredNum = valueList.get(1).trim(); String successTicketNum = valueList.get(3).trim(); log.info("Javascript code: requiredNum=" + requiredNum + ", successTicketNum=" + successTicketNum); int iTotalNum = NumberUtils.toInt(requiredNum); int iSusscessNum = NumberUtils.toInt(successTicketNum); if(iTotalNum != iSusscessNum) { log.error("iTotalNum=" + iTotalNum + " != iSusscessNum=" + iSusscessNum); return false; } return true; } private boolean isSuccessByForm(Context context, String pageContent, String charset) throws ParserException { Parser parser = MiscUtils.createParser(pageContent, charset, log); NodeFilter[] a = new NodeFilter[0]; List<NodeFilter> filters = new ArrayList<NodeFilter>(); //FAILED form filters.add(new NodeClassFilter(FormTag.class)); filters.add(new HasAttributeFilter("id", "confirmPassenger")); filters.add(new HasAttributeFilter("name", "save_passenger_single")); NodeFilter confirmPassengerFilter = new AndFilter(filters.toArray(a)); filters.clear(); //SUCCESS form filters.add(new NodeClassFilter(FormTag.class)); filters.add(new HasAttributeFilter("id", "epayForm")); NodeFilter epayFormFilter = new AndFilter(filters.toArray(a)); filters.clear(); //Final filter NodeFilter filter = new OrFilter(confirmPassengerFilter, epayFormFilter); NodeList nodeList = parser.parse(filter); FormTag failForm = null, okForm = null; for(int i = 0, size = nodeList.size(); i < size; i++) { FormTag form = (FormTag)nodeList.elementAt(i); String id = form.getAttribute("id"); log.info("Found the form '" + id + "'"); if("confirmPassenger".equals(id)) { failForm = form; isConfirmPassengerFormExist = true; } else if("epayForm".equals(id)) { okForm = form; } } if(failForm != null) { return false; } if(okForm != null) { return true; } log.warn("Can't find the epayForm. Assume success!"); return true; } private IDValuePair parseFailReason(Context context, String pageContent, String charset) throws ParserException { Parser parser = MiscUtils.createParser(pageContent, charset, log); int flags = Pattern.MULTILINE | Pattern.DOTALL; NodeFilter scriptFilter = new ScriptCodeFilter(JS_ERROR_MSG_REGEX, flags); // parse NodeList nodeList = parser.parse(scriptFilter); if(nodeList.size() < 1) { log.info("Can't find the 'message' script."); TdParams.getUI(context).error("Can't find the 'message' script."); return ResultCode.RC_TD_CONFIRM_PASSENGER_UNKOWN_ERROR; } ScriptTag js = (ScriptTag) nodeList.elementAt(0); List<String> valueList = new ArrayList<String>(); int matchCount = MiscUtils.getRegexValue(js.getScriptCode().trim(), JS_ERROR_MSG_REGEX, valueList, true, flags); if(matchCount != 1) { log.fatal("parseFailReason Unexpected: matchCount=" + matchCount); return ResultCode.RC_ASSERT_FAILURE; } String message = valueList.get(1).trim(); log.info("Javascript code: error message=" + message); IDValuePair rc = ResultCode.RC_TD_CONFIRM_PASSENGER_UNKOWN_ERROR; if(!StringUtils.isEmpty(message)) { if(message.contains(AppConfig.getInstance().getPropInternal("td.order.nok.rand_code_error"))) { rc = ResultCode.RC_RAND_CODE_ERROR; if(!isConfirmPassengerFormExist) { log.info("Rand Code error, but the Confirm Passenger Form doesn't exist"); context.remove(TdPNames._CONFIRM_PASSENGER_CONTENT); context.remove(TdPNames._CONFIRM_PASSENGER_ENCODING); } } else if(message.contains(AppConfig.getInstance().getPropInternal("td.order.nok.cancel_too_much"))) { rc = ResultCode.RC_TD_CONFIRM_PASSENGER_CANCEL_TOO_MUCH; } else if(message.contains(AppConfig.getInstance().getPropInternal("td.order.nok.repeat_buy_ticket"))) { rc = ResultCode.RC_TD_CONFIRM_PASSENGER_REPEAT_BUY_TICKET; } else if(message.contains(AppConfig.getInstance().getPropInternal("td.order.nok.card_number_error"))) { rc = ResultCode.RC_TD_CONFIRM_PASSENGER_CARD_NUMBER_ERROR; } else { rc = ResultCode.RC_TD_CONFIRM_PASSENGER_OTHER_ERROR; } } String infoMsg = MessageFormat.format(ResMgr.getString("td.msg.ticket.book.failed"), message); TdParams.getUI(context).error(infoMsg + ", rc = " + rc); return rc; } }