1
2
3
4
5
6
7
8
9
10
11 package org.mule.endpoint;
12
13 import org.mule.api.endpoint.EndpointException;
14 import org.mule.api.endpoint.EndpointURI;
15 import org.mule.util.ClassUtils;
16
17 import java.util.HashMap;
18 import java.util.Iterator;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.StringTokenizer;
23 import java.util.TreeMap;
24
25 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicReference;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class URIBuilder
45 {
46
47 private static final String DOTS = ":";
48 private static final String DOTS_SLASHES = DOTS + "//";
49 private static final String QUERY = "?";
50 private static final String AND = "&";
51 private static final String EQUALS = "=";
52
53 public static final String META = "meta";
54 public static final String PROTOCOL = "protocol";
55 public static final String USER = "user";
56 public static final String PASSWORD = "password";
57 public static final String HOST = "host";
58 public static final String ADDRESS = "address";
59 public static final String PORT = "port";
60 public static final String PATH = "path";
61
62 public static final String[] ALL_ATTRIBUTES =
63 new String[]{META, PROTOCOL, USER, PASSWORD, HOST, ADDRESS, PORT, PATH};
64
65 public static final String[] PATH_ATTRIBUTES = new String[]{PATH};
66 public static final String[] HOST_ATTRIBUTES = new String[]{HOST};
67 public static final String[] SOCKET_ATTRIBUTES = new String[]{HOST, PORT};
68 public static final String[] USERHOST_ATTRIBUTES = new String[]{USER, HOST};
69
70 public static final String[] ALL_TRANSPORT_ATTRIBUTES = new String[]{USER, PASSWORD, HOST, PORT, PATH};
71
72 private String address;
73 private String meta;
74 private String protocol;
75 private String user;
76 private String password;
77 private String host;
78 private Integer port;
79 private String path;
80 private Map queryMap;
81
82 private AtomicReference cache = new AtomicReference();
83
84 public URIBuilder()
85 {
86
87 }
88
89 public URIBuilder(EndpointURI endpointURI)
90 {
91 cache.set(endpointURI);
92 }
93
94 public URIBuilder(String address)
95 {
96
97 int dots = address.indexOf(DOTS);
98 int dotsSlashes = address.indexOf(DOTS_SLASHES);
99 if (dots > -1 && dots < dotsSlashes)
100 {
101 this.meta = address.substring(0, dots);
102 address = address.substring(dots+1);
103 }
104 this.address = address;
105 }
106
107 public void setUser(String user)
108 {
109 assertNotUsed();
110 this.user = user;
111 }
112
113 public void setPassword(String password)
114 {
115 assertNotUsed();
116 this.password = password;
117 }
118
119 public void setHost(String host)
120 {
121 assertNotUsed();
122 this.host = host;
123 }
124
125 public void setAddress(String address)
126 {
127 assertNotUsed();
128 this.address = address;
129 assertAddressConsistent();
130 }
131
132 public void setPort(int port)
133 {
134 assertNotUsed();
135 this.port = new Integer(port);
136 }
137
138 public void setProtocol(String protocol)
139 {
140 assertNotUsed();
141 this.protocol = protocol;
142 assertAddressConsistent();
143 }
144
145 public void setMeta(String meta)
146 {
147 assertNotUsed();
148 this.meta = meta;
149 }
150
151 public void setPath(String path)
152 {
153 assertNotUsed();
154 if (null != path && path.indexOf(DOTS_SLASHES) > -1)
155 {
156 throw new IllegalArgumentException("Unusual syntax in path: '" + path + "' contains " + DOTS_SLASHES);
157 }
158 this.path = path;
159 }
160
161 public void setQueryMap(Map queryMap)
162 {
163 assertNotUsed();
164 this.queryMap = queryMap;
165 }
166
167 public EndpointURI getEndpoint()
168 {
169 if (null == cache.get())
170 {
171 try
172 {
173 EndpointURI endpointUri = new MuleEndpointURI(getConstructor());
174 cache.compareAndSet(null, endpointUri);
175 }
176 catch (EndpointException e)
177 {
178 throw (IllegalStateException)new IllegalStateException("Bad endpoint configuration").initCause(e);
179 }
180 }
181 return (EndpointURI)cache.get();
182 }
183
184
185
186
187 protected String getConstructor()
188 {
189 StringBuffer buffer = new StringBuffer();
190 appendMeta(buffer);
191 OrderedQueryParameters uriQueries = appendAddress(buffer);
192 uriQueries.override(queryMap);
193 buffer.append(uriQueries.toString());
194 return buffer.toString();
195 }
196
197 private void appendMeta(StringBuffer buffer)
198 {
199 if (null != meta)
200 {
201 buffer.append(meta);
202 buffer.append(DOTS);
203 }
204 }
205
206 private OrderedQueryParameters appendAddress(StringBuffer buffer)
207 {
208 if (null != address)
209 {
210 int index = address.indexOf(QUERY);
211 if (index > -1)
212 {
213 buffer.append(address.substring(0, index));
214 return parseQueries(address.substring(index + 1));
215 }
216 else
217 {
218 buffer.append(address);
219 return new OrderedQueryParameters();
220 }
221 }
222 else
223 {
224 constructAddress(buffer);
225 return new OrderedQueryParameters();
226 }
227 }
228
229 private OrderedQueryParameters parseQueries(String queries)
230 {
231 OrderedQueryParameters map = new OrderedQueryParameters();
232 StringTokenizer query = new StringTokenizer(queries, AND);
233 while (query.hasMoreTokens())
234 {
235 StringTokenizer nameValue = new StringTokenizer(query.nextToken(), EQUALS);
236 String name = nameValue.nextToken();
237 String value = null;
238 if (nameValue.hasMoreTokens())
239 {
240 value = nameValue.nextToken();
241 }
242 map.put(name, value);
243 }
244 return map;
245 }
246
247 private void constructAddress(StringBuffer buffer)
248 {
249 buffer.append(protocol);
250 buffer.append(DOTS_SLASHES);
251 boolean atStart = true;
252 if (null != user)
253 {
254 buffer.append(user);
255 if (null != password)
256 {
257 buffer.append(":");
258 buffer.append(password);
259 }
260 buffer.append("@");
261 atStart = false;
262 }
263 if (null != host)
264 {
265 buffer.append(host);
266 if (null != port)
267 {
268 buffer.append(":");
269 buffer.append(port);
270 }
271 atStart = false;
272 }
273 if (null != path)
274 {
275 if (! atStart)
276 {
277 buffer.append("/");
278 }
279 buffer.append(path);
280 }
281 }
282
283 protected void assertNotUsed()
284 {
285 if (null != cache.get())
286 {
287 throw new IllegalStateException("Too late to set values - builder already used");
288 }
289 }
290
291 protected void assertAddressConsistent()
292 {
293 if (null != meta)
294 {
295 if (null != address)
296 {
297 if (address.startsWith(meta + DOTS))
298 {
299 throw new IllegalArgumentException("Meta-protocol '" + meta +
300 "' should not be specified in the address '" + address +
301 "' - it is implicit in the element namespace.");
302 }
303 if (null != protocol)
304 {
305 assertProtocolConsistent();
306 }
307 else
308 {
309 if (address.indexOf(DOTS_SLASHES) == -1)
310 {
311 throw new IllegalArgumentException("Address '" + address +
312 "' does not have a transport protocol prefix " +
313 "(omit the meta protocol prefix, '" + meta + DOTS +
314 "' - it is implicit in the element namespace).");
315 }
316 }
317 }
318 }
319 else
320 {
321 assertProtocolConsistent();
322 }
323 }
324
325 protected void assertProtocolConsistent()
326 {
327 if (null != protocol && null != address && !address.startsWith(protocol + DOTS_SLASHES))
328 {
329 throw new IllegalArgumentException("Address '" + address + "' for protocol '" + protocol +
330 "' should start with " + protocol + DOTS_SLASHES);
331 }
332 }
333
334 public String toString()
335 {
336 return getConstructor();
337 }
338
339 public boolean equals(Object other)
340 {
341 if (null == other || !getClass().equals(other.getClass())) return false;
342 if (this == other) return true;
343
344 URIBuilder builder = (URIBuilder) other;
345 return equal(address, builder.address)
346 && equal(meta, builder.meta)
347 && equal(protocol, builder.protocol)
348 && equal(user, builder.user)
349 && equal(password, builder.password)
350 && equal(host, builder.host)
351 && equal(port, builder.port)
352 && equal(path, builder.path)
353 && equal(queryMap, builder.queryMap);
354 }
355
356 protected static boolean equal(Object a, Object b)
357 {
358 return ClassUtils.equal(a, b);
359 }
360
361 public int hashCode()
362 {
363 return ClassUtils.hash(new Object[]{address, meta, protocol, user, password, host, port, path, queryMap});
364 }
365
366 private static class OrderedQueryParameters
367 {
368
369 private Map values = new HashMap();
370 private List orderedKeys = new LinkedList();
371
372 public void put(String name, String value)
373 {
374 values.put(name, value);
375 orderedKeys.add(name);
376 }
377
378 public void override(Map map)
379 {
380 if (null != map)
381 {
382
383 Iterator names = new TreeMap(map).keySet().iterator();
384 while (names.hasNext())
385 {
386 String name = (String) names.next();
387 String value =(String) map.get(name);
388 if (! values.keySet().contains(name))
389 {
390 orderedKeys.add(name);
391 }
392 values.put(name, value);
393 }
394 }
395 }
396
397 public String toString()
398 {
399 StringBuffer buffer = new StringBuffer();
400 Iterator keys = orderedKeys.iterator();
401 boolean first = true;
402 while (keys.hasNext())
403 {
404 if (first)
405 {
406 buffer.append(QUERY);
407 first = false;
408 }
409 else
410 {
411 buffer.append(AND);
412 }
413 String key = (String)keys.next();
414 buffer.append(key);
415 String value = (String)values.get(key);
416 if (null != value)
417 {
418 buffer.append(EQUALS);
419 buffer.append(value);
420 }
421 }
422 return buffer.toString();
423 }
424
425 }
426
427 }