View Javadoc

1   package net.sf.gaeappmanager.google.appengine;
2   
3   import java.io.InputStream;
4   import java.math.BigDecimal;
5   import java.util.regex.Matcher;
6   import java.util.regex.Pattern;
7   
8   import org.dom4j.Attribute;
9   import org.dom4j.Document;
10  import org.dom4j.Element;
11  import org.dom4j.io.DOMReader;
12  import org.w3c.tidy.Tidy;
13  
14  /**
15   * Parser of quota details HTML page.
16   * 
17   * @author Alois Belaska
18   */
19  public class QuotaDetailsParser {
20  
21  	/**
22  	 * @param el
23  	 *            processed element
24  	 * @param tag
25  	 *            tag name (td, ...)
26  	 * @param index
27  	 *            index of requested tag, begins with 0
28  	 */
29  	private Element getNthElementByTag(Element el, String tag, int index) {
30  		int idx = 0;
31  		for (Object obj : el.elements()) {
32  			Element e = (Element) obj;
33  			if (e.getName().equals(tag) && idx++ == index) {
34  				return e;
35  			}
36  		}
37  		return null;
38  	}
39  
40  	private Element getElementByTagAndValue(Element el, String tag, String value) {
41  		if (el.getName().equals(tag) && el.getStringValue().equals(value)) {
42  			return el;
43  		}
44  
45  		for (Object obj : el.elements()) {
46  			Element result = getElementByTagAndValue((Element) obj, tag, value);
47  			if (result != null) {
48  				return result;
49  			}
50  		}
51  
52  		return null;
53  	}
54  
55  	private Element getElementById(Element el, String id) {
56  		if (el.attributeCount() > 0) {
57  			Attribute attr = el.attribute("id");
58  			if (attr != null && attr.getValue().equals(id)) {
59  				return el;
60  			}
61  		}
62  
63  		for (Object obj : el.elements()) {
64  			Element result = getElementById((Element) obj, id);
65  			if (result != null) {
66  				return result;
67  			}
68  		}
69  
70  		return null;
71  	}
72  
73  	private QuotaValue parseValue(Element parentEl, Quota quota) {
74  		QuotaValue qVal = new QuotaValue();
75  		qVal.setQuota(quota);
76  
77  		Element valEl = getElementByTagAndValue(parentEl, "td", quota
78  				.getQuotaName());
79  		if (valEl == null) {
80  			return null;
81  		}
82  
83  		Element el = getNthElementByTag(valEl.getParent(), "td", 2);
84  		if (el == null) {
85  			return null;
86  		}
87  
88  		qVal
89  				.setPercent(new BigDecimal(el.getStringValue().replaceAll("%",
90  						"")));
91  
92  		el = getNthElementByTag(valEl.getParent(), "td", 3);
93  		if (el == null) {
94  			return null;
95  		}
96  
97  		String[] parts = el.getStringValue().split(" ");
98  		if (parts.length < 3) {
99  			return null;
100 		}
101 
102 		qVal.setValue(new BigDecimal(parts[0]));
103 		qVal.setLimit(new BigDecimal(parts[2]));
104 
105 		StringBuilder unitBuilder = new StringBuilder();
106 		for (int i = 3; i < parts.length; i++) {
107 			if (unitBuilder.length() > 0) {
108 				unitBuilder.append(" ");
109 			}
110 			unitBuilder.append(parts[i]);
111 		}
112 		qVal.setUnit(unitBuilder.toString());
113 
114 		el = getNthElementByTag(valEl.getParent(), "td", 4);
115 		if (el == null) {
116 			return null;
117 		}
118 
119 		qVal.setOkay(el.getStringValue().equals("Okay"));
120 
121 		return qVal;
122 	}
123 
124 	private void parseRefreshNote(Element parentEl, QuotaDetails result) {
125 		Element el = getElementById(parentEl, "ae-quota-refresh-note");
126 		if (el == null) {
127 			return;
128 		}
129 
130 		Pattern pattern = Pattern
131 				.compile("Quotas are reset every ([0-9]*) hours. Next reset: ([0-9]*) hours");
132 
133 		Matcher matcher = pattern.matcher(el.getStringValue());
134 		if (matcher.matches()) {
135 			result.setResetIntervalHours(Integer.valueOf(matcher.group(1)));
136 			result.setNextResetWithinHours(Integer.valueOf(matcher.group(2)));
137 		}
138 	}
139 
140 	public QuotaDetails parse(InputStream inputStream) {
141 		QuotaDetails result = new QuotaDetails();
142 
143 		Tidy tidy = new Tidy();
144 		tidy.setXHTML(true);
145 		tidy.setShowWarnings(false);
146 		tidy.setQuiet(true);
147 		tidy.setXmlOut(false);
148 		org.w3c.dom.Document xhtml = tidy.parseDOM(inputStream, null);
149 
150 		DOMReader xmlReader = new DOMReader();
151 		Document document = xmlReader.read(xhtml);
152 
153 		Element quotaDetailsElement = getElementById(document.getRootElement(),
154 				"ae-quota-details");
155 
156 		parseRefreshNote(quotaDetailsElement, result);
157 
158 		for (Quota quota : Quota.values()) {
159 			QuotaValue qValue = parseValue(quotaDetailsElement, quota);
160 			if (qValue != null) {
161 				result.getValues().add(qValue);
162 			}
163 		}
164 
165 		return result;
166 	}
167 }