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