package com.bao.lc.site.s2.commands; import java.io.IOException; import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.apache.commons.chain.Context; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIUtils; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.Tag; import org.htmlparser.Text; import org.htmlparser.filters.AndFilter; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.tags.LinkTag; import org.htmlparser.tags.TableColumn; import org.htmlparser.tags.TableRow; import org.htmlparser.tags.TableTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import org.htmlparser.visitors.NodeVisitor; import com.bao.lc.AppConfig; import com.bao.lc.bean.IDValuePair; import com.bao.lc.bean.ResultCode; import com.bao.lc.client.utils.HttpClientUtils; import com.bao.lc.httpcommand.BasicHttpCommand; import com.bao.lc.httpcommand.params.HttpCommandPNames; import com.bao.lc.httpcommand.params.HttpCommandParams; import com.bao.lc.site.s2.ZyConstants; import com.bao.lc.util.MiscUtils; public class QueryTicketNumResult extends BasicHttpCommand { private static Log log = LogFactory.getLog(QueryTicketNumResult.class); @Override protected IDValuePair preExecute(Context context) throws Exception { // Remove the response if it exists context.remove(HttpCommandPNames.TARGET_RESPONSE); context.remove(HttpCommandPNames.HTTP_COMMAND_RESULT_CODE); //Get target URI String encoding = MapUtils.getString(context, ZyConstants.PARAM_RSP_ENCODING, "UTF-8"); String doctor = MapUtils.getString(context, ZyConstants.PARAM_DOCTOR); String escapedName = MiscUtils.encode(doctor, encoding); String url = AppConfig.getInstance().getPropInternal("zy.query.expert.url"); url = MessageFormat.format(url, escapedName); String userPageURI = MapUtils.getString(context, ZyConstants.USER_PAGE_URI); URI baseURI = URI.create(userPageURI); URI queryURI = URIUtils.resolve(baseURI, url); context.put(HttpCommandPNames.TARGET_REQUEST, new HttpGet(queryURI)); context.put(HttpCommandPNames.TARGET_REFERER, userPageURI); return ResultCode.RC_OK; } @Override protected IDValuePair postExecute(Context context) throws Exception { // 1. Response HttpResponse rsp = HttpCommandParams.getResponse(context); // 2. parse TicketNumResult regInfo = parse(context, rsp); if(regInfo == null) { return ResultCode.RC_REG_LIST_EMPTY; } // 3. Set next hop request URI requestURI = HttpCommandParams.getTargetRequestURI(context); URI nextURI = URIUtils.resolve(requestURI, regInfo.getLink()); context.put(HttpCommandPNames.TARGET_REQUEST, new HttpGet(nextURI)); context.put(HttpCommandPNames.TARGET_REFERER, requestURI.toString()); return ResultCode.RC_OK; } private TicketNumResult parse(Context context, HttpResponse rsp) throws ParserException, IOException { String encoding = MapUtils.getString(context, ZyConstants.PARAM_RSP_ENCODING, "UTF-8"); String queryResult = HttpClientUtils.saveToString(rsp.getEntity(), encoding); Parser parser = MiscUtils.createParser(queryResult, encoding, log); // Set filters NodeFilter[] predicates = { new HasAttributeFilter("class", "datatable"), new NodeClassFilter(TableTag.class) }; NodeFilter filter = new AndFilter(predicates); NodeList dataTableList = parser.parse(filter); if(dataTableList.size() == 0) { log.info("No available reg list."); return null; } TableTag dataTable = (TableTag) dataTableList.elementAt(0); TableRow[] rows = dataTable.getRows(); if(rows.length <= 0) { log.info("No available reg list."); return null; } List<TicketNumResult> regInfoList = new ArrayList<TicketNumResult>(3); TicketNumResult regInfo = new TicketNumResult(); RegInfoVisitor visitor = new RegInfoVisitor(); for(int i = 0; i < rows.length; i++) { TableColumn[] cols = rows[i].getColumns(); for(int j = 0; j < cols.length; j++) { NodeList children = cols[j].getChildren(); visitor.setData(regInfo, i, false); children.visitAllNodesWith(visitor); if(visitor.isMeetHR()) { regInfoList.add(regInfo); regInfo = new TicketNumResult(); } } regInfo.prevText = null; } log.debug("done: " + regInfoList.size() + ", " + regInfoList.toString()); String doctor = MapUtils.getString(context, ZyConstants.PARAM_DOCTOR); String hospital = MapUtils.getString(context, ZyConstants.PARAM_HOSPITAL); for(int i = 0, size = regInfoList.size(); i < size; i++) { regInfo = regInfoList.get(i); if(StringUtils.equals(regInfo.doctor, doctor) && StringUtils.equals(regInfo.hospital, hospital) && regInfo.isAvailable()) { log.info("Found target: " + regInfo); return regInfo; } } log.info("Can't find the target registration."); return null; } private static class RegInfoVisitor extends NodeVisitor { private boolean isMeetHR = false; private int rowIndex = -1; private TicketNumResult regInfo = null; public RegInfoVisitor() { } public void setData(TicketNumResult regInfo, int rowIndex, boolean separator) { this.regInfo = regInfo; this.rowIndex = rowIndex; this.isMeetHR = separator; } public void visitTag(Tag tag) { if(tag.getTagName().equals("HR")) { isMeetHR = true; } else if(tag instanceof LinkTag) { if(StringUtils.equals(regInfo.prevText, AppConfig.getInstance().getPropInternal("zy.available.doctor.name"))) { regInfo.doctorAnchor = (LinkTag) tag; } else { regInfo.regAnchor = (LinkTag) tag; } } } public void visitStringNode(Text string) { String text = StringUtils.strip(string.getText(), " \t\r\n"); if(StringUtils.isEmpty(text)) { return; } if((rowIndex % 6) == 3) { regInfo.available = text; return; } if(StringUtils.equals(regInfo.prevText, AppConfig.getInstance().getPropInternal("zy.available.doctor.name"))) { regInfo.doctor = text; } else if(StringUtils.equals(regInfo.prevText, AppConfig.getInstance().getPropInternal("zy.available.hospital.name"))) { regInfo.hospital = text; } regInfo.prevText = text; } public boolean isMeetHR() { return isMeetHR; } } private static class TicketNumResult { public String doctor; public LinkTag doctorAnchor; public String hospital; public String available; public LinkTag regAnchor; public String prevText = null; public boolean isAvailable() { if(available == null || regAnchor == null) { return false; } if(!available .contains(AppConfig.getInstance().getPropInternal("zy.available.reg.mark"))) { return false; } String aText = StringUtils.strip(regAnchor.getStringText(), " \t\r\n"); String href = AppConfig.getInstance().getPropInternal("zy.available.link.mark"); if(!StringUtils.equals(aText, href)) { return false; } return true; } public String getLink() { if(isAvailable()) { return regAnchor.getLink(); } return null; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("doctor=").append(doctor); sb.append(",hospital=").append(hospital); sb.append(",available=").append(available); sb.append("(").append(isAvailable()).append(")"); sb.append(",regAnchor=").append(regAnchor.getLink()); sb.append(",doctorAnchor=").append(doctorAnchor.getLink()); return sb.toString(); } } }