/modules/cms-core/src/main/java/com/enonic/cms/framework/util/URL.java

https://github.com/informedindividual/cms-ce · Java · 483 lines · 395 code · 61 blank · 27 comment · 75 complexity · 7a8c05a5ed1d10e3a91075440d369ec7 MD5 · raw file

  1. /*
  2. * Copyright 2000-2011 Enonic AS
  3. * http://www.enonic.com/license
  4. */
  5. package com.enonic.cms.framework.util;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import java.util.Map;
  11. import java.util.StringTokenizer;
  12. /**
  13. * <p/> Use this class to build URLs. The functionality is <strong>very</strong> basic. Initialize it with an URL, and add new parameters
  14. * using the <code>addParameter</code> and <code>addParameters</code> method. Use the <code>setParameter</code> method to set/reset
  15. * parameters. The <code>setLabel</code> method is used to set the optional label identifier at the end of the url. </p>
  16. */
  17. public class URL
  18. {
  19. private String baseURL;
  20. private MultiValueMap queryParams = new MultiValueMap();
  21. private String label;
  22. public static class Parameter
  23. {
  24. private String key;
  25. private List values;
  26. private Parameter( String key, List values )
  27. {
  28. this.key = key;
  29. this.values = values;
  30. }
  31. public String getKey()
  32. {
  33. return key;
  34. }
  35. public List getValues()
  36. {
  37. return values;
  38. }
  39. }
  40. private static class ParameterIterator
  41. implements Iterator
  42. {
  43. private Iterator entryIterator;
  44. private ParameterIterator( MultiValueMap queryParams )
  45. {
  46. entryIterator = queryParams.entrySet().iterator();
  47. }
  48. public boolean hasNext()
  49. {
  50. return entryIterator.hasNext();
  51. }
  52. public Object next()
  53. {
  54. Map.Entry entry = (Map.Entry) entryIterator.next();
  55. String key = entry.getKey().toString();
  56. List values = (List) entry.getValue();
  57. return new Parameter( key, values );
  58. }
  59. public void remove()
  60. {
  61. entryIterator.remove();
  62. }
  63. }
  64. private class MultiValueMap
  65. extends HashMap<Object, Object>
  66. {
  67. private HashMap attributeMap = new HashMap<Object, String>();
  68. private boolean allowNullValues = false;
  69. public MultiValueMap( int initialCapacity, float loadFactor )
  70. {
  71. super( initialCapacity, loadFactor );
  72. }
  73. public MultiValueMap( int initialCapacity )
  74. {
  75. super( initialCapacity );
  76. }
  77. public MultiValueMap()
  78. {
  79. super();
  80. }
  81. public MultiValueMap( boolean allowNullValues )
  82. {
  83. super();
  84. this.allowNullValues = allowNullValues;
  85. }
  86. public MultiValueMap( Map m )
  87. {
  88. Iterator iterator = m.entrySet().iterator();
  89. while ( iterator.hasNext() )
  90. {
  91. Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) iterator.next();
  92. put( entry.getKey(), entry.getValue() );
  93. }
  94. }
  95. public Object put( Object key, Object value )
  96. {
  97. return put( key, value, null, false );
  98. }
  99. public Object put( Object key, Object value, String attribute )
  100. {
  101. return put( key, value, attribute, false );
  102. }
  103. public Object put( Object key, int value )
  104. {
  105. return put( key, value, null, false );
  106. }
  107. public Object put( Object key, int value, String attribute )
  108. {
  109. return put( key, value, attribute, false );
  110. }
  111. public Object put( Object key, int[] values )
  112. {
  113. return put( key, values, null );
  114. }
  115. public Object put( Object key, int[] values, String attribute )
  116. {
  117. if ( values == null )
  118. {
  119. return put( key, null, attribute, false );
  120. }
  121. Object obj = null;
  122. for ( int i = 0; i < values.length; i++ )
  123. {
  124. if ( i == 0 )
  125. {
  126. obj = put( key, values[0], false );
  127. }
  128. else
  129. {
  130. put( key, values[i], attribute, false );
  131. }
  132. }
  133. return obj;
  134. }
  135. public Object put( Object key, boolean value )
  136. {
  137. return put( key, value, null, false );
  138. }
  139. public Object put( Object key, boolean value, String attribute )
  140. {
  141. return put( key, value, attribute, false );
  142. }
  143. public Object put( Object key, Object value, boolean removeOld )
  144. {
  145. return put( key, value, null, removeOld );
  146. }
  147. public Object put( Object key, Object value, String attribute, boolean removeOld )
  148. {
  149. Object obj;
  150. if ( !removeOld && containsKey( key ) && ( value != null || allowNullValues ) )
  151. {
  152. List<Object> values = (List<Object>) get( key );
  153. if ( value instanceof ArrayList )
  154. {
  155. values.addAll( (ArrayList) value );
  156. }
  157. else
  158. {
  159. values.add( value );
  160. }
  161. obj = values;
  162. }
  163. else if ( value != null && value instanceof ArrayList )
  164. {
  165. obj = super.put( key, value );
  166. }
  167. else
  168. {
  169. List<Object> values = new ArrayList<Object>();
  170. if ( value != null || allowNullValues )
  171. {
  172. values.add( value );
  173. }
  174. obj = super.put( key, values );
  175. }
  176. if ( attribute != null )
  177. {
  178. attributeMap.put( key, attribute );
  179. }
  180. return obj;
  181. }
  182. public List getValueList( Object key )
  183. {
  184. return (List) get( key );
  185. }
  186. public String getAttribute( Object key )
  187. {
  188. return (String) attributeMap.get( key );
  189. }
  190. public boolean containsValue( Object value )
  191. {
  192. Iterator iterator = super.values().iterator();
  193. while ( iterator.hasNext() )
  194. {
  195. List values = (List) iterator.next();
  196. if ( values.contains( value ) )
  197. {
  198. return true;
  199. }
  200. }
  201. return false;
  202. }
  203. }
  204. public URL( String url )
  205. {
  206. if ( url != null && url.trim().length() > 0 )
  207. {
  208. String urlString;
  209. int labelIndex = url.indexOf( '#' );
  210. if ( labelIndex >= 0 )
  211. {
  212. this.label = url.substring( labelIndex + 1 );
  213. urlString = url.substring( 0, labelIndex );
  214. }
  215. else
  216. {
  217. urlString = url;
  218. }
  219. StringTokenizer tokenizer = new StringTokenizer( urlString, "?" );
  220. this.baseURL = tokenizer.nextToken();
  221. if ( tokenizer.hasMoreTokens() )
  222. {
  223. String queryString = tokenizer.nextToken( "" ).substring( 1 );
  224. tokenizer = new StringTokenizer( queryString, "&" );
  225. while ( tokenizer.hasMoreTokens() )
  226. {
  227. String token = tokenizer.nextToken();
  228. String name;
  229. String value = null;
  230. int equalIdx = token.indexOf( '=' );
  231. if ( equalIdx == -1 )
  232. {
  233. name = token;
  234. }
  235. else
  236. {
  237. name = token.substring( 0, equalIdx );
  238. value = token.substring( equalIdx + 1 );
  239. }
  240. if ( value != null )
  241. {
  242. queryParams.put( name, value );
  243. }
  244. }
  245. }
  246. }
  247. else
  248. {
  249. throw new IllegalArgumentException( "URL cannot be empty" );
  250. }
  251. }
  252. public URL( StringBuffer url )
  253. {
  254. this( url.toString() );
  255. }
  256. /**
  257. * Add a parameter. It will be appended to the URL string as a "name=value" pair. Previously added parameters with the same name are
  258. * preserved, as multiple values pr. name is allowed.
  259. *
  260. * @param name String
  261. * @param value String
  262. * @return <code>true</code> if the value was added, <code>false</code> otherwise.
  263. */
  264. public boolean addParameter( String name, String value )
  265. {
  266. if ( name == null || name.length() == 0 )
  267. {
  268. return false;
  269. }
  270. if ( value == null || value.length() == 0 )
  271. {
  272. return false;
  273. }
  274. queryParams.put( UrlPathEncoder.encode( name ), UrlPathEncoder.encode( value ) );
  275. return true;
  276. }
  277. public void addParameters( Map valueMap )
  278. {
  279. for ( Object key : valueMap.keySet() )
  280. {
  281. Object value = valueMap.get( key );
  282. if ( value instanceof String[] )
  283. {
  284. String[] values = (String[]) value;
  285. for ( String v : values )
  286. {
  287. queryParams.put( UrlPathEncoder.encode( key.toString() ), UrlPathEncoder.encode( v ) );
  288. }
  289. }
  290. else
  291. {
  292. queryParams.put( UrlPathEncoder.encode( key.toString() ), UrlPathEncoder.encode( value.toString() ) );
  293. }
  294. }
  295. }
  296. /**
  297. * Add parameters from av multi-value map. Iterates over the map's values and append them to the URL string as "name=value" pairs.
  298. * Previously added parameters with the same names as those added are preserved, as multiple values pr. name is allowed.
  299. *
  300. * @param valueMap MultiValueMap
  301. */
  302. public void addParameters( MultiValueMap valueMap )
  303. {
  304. for ( Object key : valueMap.keySet() )
  305. {
  306. for ( Object value : ( valueMap.getValueList( key ) ) )
  307. {
  308. queryParams.put( UrlPathEncoder.encode( key.toString() ), UrlPathEncoder.encode( value.toString() ) );
  309. }
  310. }
  311. }
  312. public boolean setParameter( String name, int value )
  313. {
  314. return setParameter( name, String.valueOf( value ) );
  315. }
  316. public boolean setParameter( String name, String value )
  317. {
  318. if ( name == null || name.length() == 0 )
  319. {
  320. return false;
  321. }
  322. if ( value == null || value.length() == 0 )
  323. {
  324. queryParams.put( UrlPathEncoder.encode( name ), "", true );
  325. }
  326. else
  327. {
  328. queryParams.put( UrlPathEncoder.encode( name ), UrlPathEncoder.encode( value ), true );
  329. }
  330. return true;
  331. }
  332. public List getParameters( String name )
  333. {
  334. if ( name == null || name.length() == 0 )
  335. {
  336. return null;
  337. }
  338. return queryParams.getValueList( name );
  339. }
  340. public MultiValueMap getParameterMap()
  341. {
  342. return queryParams;
  343. }
  344. public String getParameter( String name )
  345. {
  346. if ( name == null || name.length() == 0 )
  347. {
  348. return null;
  349. }
  350. List valueList = queryParams.getValueList( name );
  351. if ( valueList != null && valueList.size() > 0 )
  352. {
  353. return (String) valueList.get( 0 );
  354. }
  355. else
  356. {
  357. return null;
  358. }
  359. }
  360. public void removeParameter( String name )
  361. {
  362. if ( name == null || name.length() == 0 )
  363. {
  364. return;
  365. }
  366. queryParams.remove( name );
  367. }
  368. public Iterator parameterIterator()
  369. {
  370. return new ParameterIterator( queryParams );
  371. }
  372. public String toString()
  373. {
  374. StringBuffer url = new StringBuffer( baseURL );
  375. Iterator keyIterator = queryParams.keySet().iterator();
  376. boolean firstParam = true;
  377. while ( keyIterator.hasNext() )
  378. {
  379. String key = (String) keyIterator.next();
  380. for ( Object value : queryParams.getValueList( key ) )
  381. {
  382. if ( firstParam )
  383. {
  384. url.append( '?' );
  385. firstParam = false;
  386. }
  387. else
  388. {
  389. url.append( '&' );
  390. }
  391. url.append( key );
  392. url.append( '=' );
  393. url.append( value );
  394. }
  395. }
  396. if ( label != null )
  397. {
  398. if ( firstParam )
  399. {
  400. // First param has still not been added, so there are no parameters and the & is not needed.
  401. url.append( "#" );
  402. }
  403. else
  404. {
  405. // HACK: adds an extra '&' to the URL to bypass the bug concerning
  406. // request.sendRedirect()
  407. // and Internet Explorer
  408. url.append( "&#" );
  409. }
  410. url.append( label );
  411. }
  412. return url.toString();
  413. }
  414. public void setLabel( String string )
  415. {
  416. label = string;
  417. }
  418. public boolean hasParameter( String name )
  419. {
  420. return queryParams.containsKey( name );
  421. }
  422. }