1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.magicproject.database;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24
25 import net.sf.magicproject.clickable.targetable.card.CardModel;
26 import net.sf.magicproject.database.data.TranslatableData;
27 import net.sf.magicproject.management.MonitoredCheckContent;
28 import net.sf.magicproject.xml.XmlParser.Node;
29
30 /***
31 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
32 * @since 0.90
33 */
34 class UrlTokenizer {
35
36 private List<String> constraints;
37
38 private List<String> streamStrings;
39
40 UrlTokenizer(Node node) {
41 String stream = node.getAttribute("url");
42 constraints = new ArrayList<String>();
43 streamStrings = new ArrayList<String>();
44 int constraintIndex = -1;
45 int streamIndex = 0;
46 while ((constraintIndex = stream.indexOf("${", constraintIndex)) != -1) {
47 int closingBrace = stream.indexOf("}", constraintIndex);
48 if (closingBrace == -1) {
49 throw new InternalError("Unclosed '{' in stream : " + stream);
50 }
51 String constraint = stream.substring(constraintIndex + 2, closingBrace)
52 .trim().toLowerCase();
53 if (constraint.contains("+")) {
54
55 constraints
56 .add(constraint.substring(0, constraint.indexOf('+')).trim());
57 streamStrings.add(stream.substring(streamIndex, constraintIndex));
58 streamStrings.add("%ADD%");
59 constraints.add(constraint.substring(constraint.indexOf('+') + 1)
60 .trim());
61 } else {
62 constraints.add(constraint);
63 streamStrings.add(stream.substring(streamIndex, constraintIndex));
64 }
65 constraintIndex = closingBrace + 1;
66 streamIndex = constraintIndex;
67 }
68 streamStrings.add(stream.substring(streamIndex));
69 }
70
71 /***
72 * Given a scrore depending of accessible constraint within the given
73 * properties. Currently, score is
74 * <ul>
75 * <li><code>-1</code> for a not valid stream : constraints have not been
76 * all been found in the given properties</li>
77 * <li><code>0</code> for a valid stream : constraints have not all been
78 * found in the given properties</li>
79 * <li><code>positive number</code> for a valid stream with so much
80 * constraints (better) </li>
81 * </ul>
82 *
83 * @param properties
84 * set of available properties.
85 * @return the score.
86 */
87 public int getUrlScore(Map<String, String> properties) {
88 boolean hasCardNameAttr = false;
89 for (String constraint : constraints) {
90 if ("card.name".equals(constraint)) {
91 hasCardNameAttr = true;
92 } else {
93 if (properties == null || !properties.containsKey(constraint)) {
94 return -1;
95 }
96 }
97 }
98 if (properties == null) {
99 return hasCardNameAttr ? 0 : 1;
100 }
101 return properties.size() + constraints.size() + (hasCardNameAttr ? 1 : 0);
102 }
103
104 /***
105 * Return an URL built from the expression, card, constraints, and proxy.
106 *
107 * @param cardModel
108 * the card represented by the built url.
109 * @param properties
110 * the properties used to replace requested properties within the
111 * expression.
112 * @param proxy
113 * the proxy containing the requested url. Would be used to get local
114 * values.
115 * @return an URL built from the expression.
116 */
117 public String getUrl(CardModel cardModel, Map<String, ?> properties,
118 Proxy proxy) {
119 final StringBuilder res = new StringBuilder(100);
120 res.append(streamStrings.get(0));
121 for (int i = 0; i < constraints.size(); i++) {
122 final String constrainValue = getConstraint(constraints.get(i),
123 cardModel, properties, proxy);
124 if (constrainValue == null) {
125 throw new RuntimeException("URL constraint #" + i + " '"
126 + this.constraints.get(i) + "' is not defined in given card ["
127 + cardModel + "] properties " + properties.values().toString());
128 }
129 if (i < constraints.size() - 1
130 && "%ADD%".equals(streamStrings.get(i + 1))) {
131 res.append(String.valueOf(Integer.parseInt(constrainValue)
132 + Integer.parseInt(getConstraint(constraints.get(i + 1), cardModel,
133 properties, proxy)) - 1));
134 i++;
135 } else {
136 if (res.toString().contains(MonitoredCheckContent.STR_ZIP_PATH)) {
137 res.append(constrainValue);
138 } else {
139 res.append(getJspUrl(constrainValue));
140 }
141 }
142 res.append(streamStrings.get(i + 1));
143 }
144 return res.toString();
145 }
146
147 private String getConstraint(String constraint, CardModel cardModel,
148 Map<String, ?> constraints, Proxy proxy) {
149 if ("card.name".equals(constraint)) {
150 return cardModel.getCardName();
151 }
152 if ("card.keyname".equals(constraint)) {
153 return cardModel.getKeyName();
154 }
155 if ("card.language".equals(constraint)) {
156 return cardModel.getLanguage();
157 }
158 if (constraints == null || constraints.get(constraint) == null) {
159
160 return null;
161 }
162 final Object value = constraints.get(constraint);
163 if (value instanceof String) {
164 return (String) value;
165 }
166 if (proxy != null) {
167 return proxy.getLocalValueFromGlobal(constraint,
168 ((TranslatableData) value).getValue());
169 }
170 return ((TranslatableData) value).getValue();
171 }
172
173 /***
174 * Return the given string with all specials chars replaced by "%.." string
175 *
176 * @param bruteString
177 * the String to be parsed.
178 * @return the given string transformed to suit to an URL address.
179 */
180 private String getJspUrl(String bruteString) {
181 return bruteString.trim().replace(" ", "%20").replace("!", "%21").replace(
182 "\"", "%22").replace("#", "%23").replace("&", "%26")
183 .replace("'", "%27").replace("(", "%28").replace(")", "%29").replace(
184 "*", "%2A").replace("+", "%2B").replace(",", "%2C").replace("-",
185 "%2D").replace(".", "%2E").replace("/", "%2F").replace(":", "%3A")
186 .replace(";", "%3B").replace("<", "%3C").replace("=", "%3D").replace(
187 ">", "%3E").replace("@", "%41").replace("^", "%5E").replace("_",
188 "%60").replace("`", "%61").replace("{", "%7B").replace("}", "%7C")
189 .replace("|", "%7D").replace("~", "%7E");
190 }
191
192 @Override
193 public String toString() {
194 return "{streamStrings=" + streamStrings + ", constraints=" + constraints
195 + "}";
196 }
197
198 }