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