Author: ivaynberg
Date: Sun Nov  1 17:12:13 2009
New Revision: 831710

URL: http://svn.apache.org/viewvc?rev=831710&view=rev
Log:
optimization tweaks for Url

Modified:
    wicket/trunk/wicket/.settings/org.eclipse.jdt.core.prefs
    wicket/trunk/wicket/.settings/org.eclipse.jdt.ui.prefs
    wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/Url.java

Modified: wicket/trunk/wicket/.settings/org.eclipse.jdt.core.prefs
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/.settings/org.eclipse.jdt.core.prefs?rev=831710&r1=831709&r2=831710&view=diff
==============================================================================
--- wicket/trunk/wicket/.settings/org.eclipse.jdt.core.prefs (original)
+++ wicket/trunk/wicket/.settings/org.eclipse.jdt.core.prefs Sun Nov  1 
17:12:13 2009
@@ -1,4 +1,4 @@
-#Wed Sep 10 11:28:56 PDT 2008
+#Sun Oct 25 10:35:43 PDT 2009
 eclipse.preferences.version=1
 instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
 org.eclipse.jdt.core.builder.cleanOutputFolder=clean
@@ -97,15 +97,15 @@
 
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_assignment=0
 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=20
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48
 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
 
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
 
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
 
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=80
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=64
 
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
 
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=64
 
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
@@ -146,9 +146,9 @@
 org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
 org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
 org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.line_length=80
 org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=1
+org.eclipse.jdt.core.formatter.continuation_indentation=2
 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
 
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
@@ -163,6 +163,9 @@
 org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
 org.eclipse.jdt.core.formatter.indentation.size=4
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do
 not insert
 
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do
 not insert
 org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do 
not insert
 
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
@@ -331,19 +334,21 @@
 
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do
 not insert
 
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do
 not insert
 
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do
 not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
 org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
 org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
 org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
 org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
 org.eclipse.jdt.core.formatter.lineSplit=100
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=true
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
 
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=2
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.jdt.core.formatter.tabulation.char=tab
 org.eclipse.jdt.core.formatter.tabulation.size=4
 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
 org.eclipse.jdt.core.incompatibleJDKLevel=ignore
 org.eclipse.jdt.core.incompleteClasspath=error

Modified: wicket/trunk/wicket/.settings/org.eclipse.jdt.ui.prefs
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/.settings/org.eclipse.jdt.ui.prefs?rev=831710&r1=831709&r2=831710&view=diff
==============================================================================
--- wicket/trunk/wicket/.settings/org.eclipse.jdt.ui.prefs (original)
+++ wicket/trunk/wicket/.settings/org.eclipse.jdt.ui.prefs Sun Nov  1 17:12:13 
2009
@@ -1,4 +1,4 @@
-#Wed Aug 01 11:37:07 CEST 2007
+#Sun Oct 25 10:35:43 PDT 2009
 comment_clear_blank_lines=false
 comment_format_comments=true
 comment_format_header=true
@@ -11,7 +11,7 @@
 comment_separate_root_tags=true
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_wicket
+formatter_profile=_Wicket
 formatter_settings_version=11
 instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
 org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" 
encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="false" 
context\="gettercomment_context" deleted\="false" description\="Comment for 
getter method" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" 
name\="gettercomment">/**\r\n * Gets ${bare_field_name}.\r\n * @return 
${bare_field_name}\r\n */</template><template autoinsert\="false" 
context\="settercomment_context" deleted\="false" description\="Comment for 
setter method" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" 
name\="settercomment">/**\r\n * Sets ${bare_field_name}.\r\n * @param ${param} 
${bare_field_name}\r\n */</template><template autoinsert\="false" 
context\="constructorcomment_context" deleted\="false" description\="Comment 
for created constructors" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" 
name\="constructorcomment">/**\r\n * Construct.\r\n
  * ${tags}\r\n */</template><template autoinsert\="false" 
context\="filecomment_context" deleted\="false" description\="Comment for 
created Java files" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" 
name\="filecomment"/><template autoinsert\="false" 
context\="typecomment_context" deleted\="false" description\="Comment for 
created types" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" 
name\="typecomment">/**\r\n * @author ${user}\r\n * ${tags}\r\n 
*/</template><template autoinsert\="true" context\="fieldcomment_context" 
deleted\="false" description\="Comment for fields" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" 
name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" 
context\="methodcomment_context" deleted\="false" description\="Comment for 
non-overriding methods" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" 
name\="methodcomment">/**\r\n * ${tags}
 \r\n */</template><template autoinsert\="false" 
context\="overridecomment_context" deleted\="false" description\="Comment for 
overriding methods" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" 
name\="overridecomment">/**\r\n * ${see_to_overridden}\r\n 
*/</template><template autoinsert\="false" context\="newtype_context" 
deleted\="false" description\="Newly created files" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">/*\r\n * 
Licensed to the Apache Software Foundation (ASF) under one or more\r\n * 
contributor license agreements.  See the NOTICE file distributed with\r\n * 
this work for additional information regarding copyright ownership.\r\n * The 
ASF licenses this file to You under the Apache License, Version 2.0\r\n * (the 
"License"); you may not use this file except in compliance with\r\n * the 
License.  You may obtain a copy of the License at\r\n *\r\n *      
http\://www.apache.org/licenses/LICENSE-2.0\r\
 n *\r\n * Unless required by applicable law or agreed to in writing, 
software\r\n * distributed under the License is distributed on an "AS IS" 
BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
implied.\r\n * See the License for the specific language governing permissions 
and\r\n * limitations under the License.\r\n 
*/\r\n${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template
 autoinsert\="false" context\="catchblock_context" deleted\="false" 
description\="Code in new catch blocks" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">throw 
new RuntimeException(${exception_var});</template><template autoinsert\="false" 
context\="methodbody_context" deleted\="false" description\="Code in created 
method stubs" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" 
name\="methodbody">${body_statement}</template><template autoinsert\="false" 
context\="c
 onstructorbody_context" deleted\="false" description\="Code in created 
constructor stubs" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" 
name\="constructorbody">${body_statement}</template><template 
autoinsert\="true" context\="getterbody_context" deleted\="false" 
description\="Code in created getters" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" 
name\="getterbody">return ${field};</template><template autoinsert\="true" 
context\="setterbody_context" deleted\="false" description\="Code in created 
setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" 
name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" 
context\="classbody_context" deleted\="false" description\="Code in new class 
type bodies" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.classbody" 
name\="classbody">\r\n</template><template autoinsert\="true" 
context\="interfacebody_context" deleted\="false" 
 description\="Code in new interface type bodies" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" 
name\="interfacebody">\r\n</template><template autoinsert\="true" 
context\="enumbody_context" deleted\="false" description\="Code in new enum 
type bodies" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" 
name\="enumbody">\r\n</template><template autoinsert\="true" 
context\="annotationbody_context" deleted\="false" description\="Code in new 
annotation type bodies" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" 
name\="annotationbody">\r\n</template><template autoinsert\="true" 
context\="delegatecomment_context" deleted\="false" description\="Comment for 
delegate methods" enabled\="true" 
id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" 
name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n 
*/</template></templates>

Modified: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/Url.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/Url.java?rev=831710&r1=831709&r2=831710&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/Url.java 
(original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/Url.java Sun 
Nov  1 17:12:13 2009
@@ -46,433 +46,439 @@
  *                                                an additional slash, i.e. //
  * </pre>
  * 
- * The Url class takes care of encoding and decoding of the segments and 
parameters.
+ * The Url class takes care of encoding and decoding of the segments and
+ * parameters.
  * 
  * @author Matej Knopp
  * @author Igor Vaynberg
  */
 public final class Url implements Serializable
 {
-    private static final long serialVersionUID = 1L;
+       private static final long serialVersionUID = 1L;
 
-    private final List<String> segments = new ArrayList<String>();
+       private final List<String> segments = new ArrayList<String>();
 
-    private List<QueryParameter> parameters = new ArrayList<QueryParameter>();
+       private final List<QueryParameter> parameters = new 
ArrayList<QueryParameter>();
 
-    /**
-     * Construct.
-     */
-    public Url()
-    {
-    }
-
-    /**
-     * Construct.
-     * 
-     * @param url
-     *            url being copied
-     */
-    public Url(Url url)
-    {
-        Checks.argumentNotNull(url, "url");
-
-        segments.addAll(url.getSegments());
-        parameters.addAll(url.getQueryParameters());
-    }
-
-    /**
-     * Construct.
-     * 
-     * @param segments
-     * @param parameters
-     */
-    public Url(List<String> segments, List<QueryParameter> parameters)
-    {
-        Checks.argumentNotNull(segments, "segments");
-        Checks.argumentNotNull(parameters, "parameters");
-
-        this.segments.addAll(segments);
-        this.parameters.addAll(parameters);
-    }
-
-    /**
-     * Returns segments of the URL. Segments form the part before query string.
-     * 
-     * @return mutable list of segments
-     */
-    public List<String> getSegments()
-    {
-        return segments;
-    }
-
-    /**
-     * Returns query parameters of the URL.
-     * 
-     * @return mutable list of query parameters
-     */
-    public List<QueryParameter> getQueryParameters()
-    {
-        return parameters;
-    }
-
-    /**
-     * Returns whether the URL is absolute.
-     * 
-     * @return <code>true</code> if URL is absolute, <code>false</code> 
otherwise.
-     */
-    public boolean isAbsolute()
-    {
-        return !getSegments().isEmpty() && 
Strings.isEmpty(getSegments().get(0));
-    }
-
-    /**
-     * Convenience method that removes all query parameters with given name.
-     * 
-     * @param name
-     *            query parameter name
-     */
-    public void removeQueryParameters(String name)
-    {
-        for (Iterator<QueryParameter> i = getQueryParameters().iterator(); 
i.hasNext();)
-        {
-            QueryParameter param = i.next();
-            if (Objects.equal(name, param.getName()))
-            {
-                i.remove();
-            }
-        }
-    }
-
-    /**
-     * Convenience method that removes <code>count</code> leading segments
-     * 
-     * @param count
-     */
-    public void removeLeadingSegments(int count)
-    {
-        Checks.argumentWithinRange(0, segments.size(), count, "count");
-        for (int i = 0; i < count; i++)
-        {
-            segments.remove(0);
-        }
-    }
-
-    /**
-     * Convenience method that prepends <code>segments</code> to the segments 
collection
-     * 
-     * @param newSegments
-     */
-    public void prependLeadingSegments(List<String> newSegments)
-    {
-        Checks.argumentNotNull(newSegments, "segments");
-        segments.addAll(0, newSegments);
-    }
-
-    /**
-     * Convenience method that removes all query parameters with given name 
and adds new query
-     * parameter with specified name and value
-     * 
-     * @param name
-     * @param value
-     */
-    public void setQueryParameter(String name, Object value)
-    {
-        removeQueryParameters(name);
-        if (value != null)
-        {
-            QueryParameter parameter = new QueryParameter(name, 
value.toString());
-            getQueryParameters().add(parameter);
-        }
-    }
-
-    /**
-     * Returns first query parameter with specified name or null if such query 
parameter doesn't
-     * exist.
-     * 
-     * @param name
-     * @return query parameter or <code>null</code>
-     */
-    public QueryParameter getQueryParameter(String name)
-    {
-        for (QueryParameter parameter : parameters)
-        {
-            if (Objects.equal(name, parameter.getName()))
-            {
-                return parameter;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the value of first query parameter with specified name. Note 
that this method never
-     * returns <code>null</code>. Not even if the parameter does not exist.
-     * 
-     * @see StringValue#isNull()
-     * 
-     * @param name
-     * @return {...@link StringValue} instance wrapping the parameter value
-     */
-    public StringValue getQueryParameterValue(String name)
-    {
-        QueryParameter parameter = getQueryParameter(name);
-        if (parameter == null)
-        {
-            return StringValue.valueOf((String)null);
-        }
-        else
-        {
-            return StringValue.valueOf(parameter.getValue());
-        }
-    }
-
-    /**
-     * Represents a single query parameter
-     * 
-     * @author Matej Knopp
-     */
-    public final static class QueryParameter
-    {
-        private final String name;
-        private final String value;
-
-        /**
-         * Creates new {...@link QueryParameter} instance. The 
<code>name</code> and <code>value</code>
-         * parameters must not be <code>null</code>, though they can be empty 
strings.
-         * 
-         * @param name
-         *            parameter name
-         * @param value
-         *            parameter value
-         */
-        public QueryParameter(String name, String value)
-        {
-            Checks.argumentNotNull(name, "name");
-            Checks.argumentNotNull(value, "value");
-
-            this.name = name;
-            this.value = value;
-        }
-
-        /**
-         * Returns query parameter name.
-         * 
-         * @return query parameter name
-         */
-        public String getName()
-        {
-            return name;
-        }
-
-        /**
-         * Returns query parameter value.
-         * 
-         * @return query parameter value
-         */
-        public String getValue()
-        {
-            return value;
-        }
-
-        @Override
-        public boolean equals(Object obj)
-        {
-            if (this == obj)
-            {
-                return true;
-            }
-            if (obj instanceof QueryParameter == false)
-            {
-                return false;
-            }
-            QueryParameter rhs = (QueryParameter)obj;
-            return Objects.equal(this.getName(), rhs.getName()) &&
-                    Objects.equal(this.getValue(), rhs.getValue());
-        }
-
-        @Override
-        public int hashCode()
-        {
-            return Objects.hashCode(getName(), getValue());
-        }
-
-        @Override
-        public String toString()
-        {
-            StringBuilder result = new StringBuilder();
-            result.append(encodeParameter(getName()));
-            if (!Strings.isEmpty(getValue()))
-            {
-                result.append('=');
-                result.append(encodeParameter(getValue()));
-            }
-            return result.toString();
-        }
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-        {
-            return true;
-        }
-        if (obj instanceof Url == false)
-        {
-            return false;
-        }
-        Url rhs = (Url)obj;
-
-        return getSegments().equals(rhs.getSegments()) &&
-                getQueryParameters().equals(rhs.getQueryParameters());
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return Objects.hashCode(getSegments(), getQueryParameters());
-    }
-
-    private static String encodeSegment(String string)
-    {
-        return WicketURLEncoder.PATH_INSTANCE.encode(string);
-    }
-
-    private static String decodeSegment(String string)
-    {
-        return WicketURLDecoder.PATH_INSTANCE.decode(string);
-    }
-
-    private static String encodeParameter(String string)
-    {
-        return WicketURLEncoder.QUERY_INSTANCE.encode(string);
-    }
-
-    private static String decodeParameter(String string)
-    {
-        return WicketURLDecoder.QUERY_INSTANCE.decode(string);
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder result = new StringBuilder();
-        boolean first = true;
-        for (String s : getSegments())
-        {
-            if (!first)
-            {
-                result.append('/');
-            }
-            first = false;
-            result.append(encodeSegment(s));
-        }
-
-        first = true;
-
-        for (QueryParameter p : getQueryParameters())
-        {
-            if (first)
-            {
-                result.append("?");
-                first = false;
-            }
-            else
-            {
-                result.append("&");
-            }
-            result.append(p.toString());
-        }
-
-        return result.toString();
-    }
-
-    private static QueryParameter parseQueryParameter(String qp)
-    {
-        if (qp.indexOf('=') == -1)
-        {
-            return new QueryParameter(decodeParameter(qp), "");
-        }
-        String parts[] = qp.split("=");
-        if (parts.length == 0)
-        {
-            return new QueryParameter("", "");
-        }
-        else if (parts.length == 1)
-        {
-            return new QueryParameter("", decodeParameter(parts[0]));
-        }
-        else
-        {
-            return new QueryParameter(decodeParameter(parts[0]), 
decodeParameter(parts[1]));
-        }
-    }
-
-    /**
-     * Parses the given URL string.
-     * 
-     * @param url
-     * @return Url object
-     */
-    public static Url parse(String url)
-    {
-        Checks.argumentNotNull(url, "url");
-
-        Url result = new Url();
-
-        String segments;
-        String query;
-
-        int qIndex = url.indexOf('?');
-
-        if (qIndex == -1)
-        {
-            segments = url;
-            query = "";
-        }
-        else
-        {
-            segments = url.substring(0, qIndex);
-            query = url.substring(qIndex + 1);
-        }
-
-        if (segments.length() > 0)
-        {
-
-            boolean removeLast = false;
-            if (segments.endsWith("/"))
-            {
-                // we need to append something and remove it after splitting 
because otherwise the
-                // trailing slashes will be lost
-                segments += "/x";
-                removeLast = true;
-            }
-
-            String segmentArray[] = segments.split("/");
-
-            if (removeLast)
-            {
-                segmentArray[segmentArray.length - 1] = null;
-            }
-
-            for (String s : segmentArray)
-            {
-                if (s != null)
-                {
-                    result.segments.add(decodeSegment(s));
-                }
-            }
-        }
-
-        if (query.length() > 0)
-        {
-            String queryArray[] = query.split("&");
-            for (String s : queryArray)
-            {
-                result.parameters.add(parseQueryParameter(s));
-            }
-        }
+       /**
+        * Construct.
+        */
+       public Url()
+       {
+       }
+
+       /**
+        * Construct.
+        * 
+        * @param url
+        *            url being copied
+        */
+       public Url(Url url)
+       {
+               Checks.argumentNotNull(url, "url");
+
+               segments.addAll(url.getSegments());
+               parameters.addAll(url.getQueryParameters());
+       }
+
+       /**
+        * Construct.
+        * 
+        * @param segments
+        * @param parameters
+        */
+       public Url(List<String> segments, List<QueryParameter> parameters)
+       {
+               Checks.argumentNotNull(segments, "segments");
+               Checks.argumentNotNull(parameters, "parameters");
+
+               this.segments.addAll(segments);
+               this.parameters.addAll(parameters);
+       }
+
+       /**
+        * Returns segments of the URL. Segments form the part before query 
string.
+        * 
+        * @return mutable list of segments
+        */
+       public List<String> getSegments()
+       {
+               return segments;
+       }
+
+       /**
+        * Returns query parameters of the URL.
+        * 
+        * @return mutable list of query parameters
+        */
+       public List<QueryParameter> getQueryParameters()
+       {
+               return parameters;
+       }
+
+       /**
+        * Returns whether the URL is absolute.
+        * 
+        * @return <code>true</code> if URL is absolute, <code>false</code>
+        *         otherwise.
+        */
+       public boolean isAbsolute()
+       {
+               return !getSegments().isEmpty() && 
Strings.isEmpty(getSegments().get(0));
+       }
+
+       /**
+        * Convenience method that removes all query parameters with given name.
+        * 
+        * @param name
+        *            query parameter name
+        */
+       public void removeQueryParameters(String name)
+       {
+               for (Iterator<QueryParameter> i = 
getQueryParameters().iterator(); i.hasNext();)
+               {
+                       QueryParameter param = i.next();
+                       if (Objects.equal(name, param.getName()))
+                       {
+                               i.remove();
+                       }
+               }
+       }
+
+       /**
+        * Convenience method that removes <code>count</code> leading segments
+        * 
+        * @param count
+        */
+       public void removeLeadingSegments(int count)
+       {
+               Checks.argumentWithinRange(0, segments.size(), count, "count");
+               for (int i = 0; i < count; i++)
+               {
+                       segments.remove(0);
+               }
+       }
+
+       /**
+        * Convenience method that prepends <code>segments</code> to the 
segments
+        * collection
+        * 
+        * @param newSegments
+        */
+       public void prependLeadingSegments(List<String> newSegments)
+       {
+               Checks.argumentNotNull(newSegments, "segments");
+               segments.addAll(0, newSegments);
+       }
+
+       /**
+        * Convenience method that removes all query parameters with given name 
and
+        * adds new query parameter with specified name and value
+        * 
+        * @param name
+        * @param value
+        */
+       public void setQueryParameter(String name, Object value)
+       {
+               removeQueryParameters(name);
+               if (value != null)
+               {
+                       QueryParameter parameter = new QueryParameter(name, 
value.toString());
+                       getQueryParameters().add(parameter);
+               }
+       }
+
+       /**
+        * Returns first query parameter with specified name or null if such 
query
+        * parameter doesn't exist.
+        * 
+        * @param name
+        * @return query parameter or <code>null</code>
+        */
+       public QueryParameter getQueryParameter(String name)
+       {
+               for (QueryParameter parameter : parameters)
+               {
+                       if (Objects.equal(name, parameter.getName()))
+                       {
+                               return parameter;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Returns the value of first query parameter with specified name. Note 
that
+        * this method never returns <code>null</code>. Not even if the 
parameter
+        * does not exist.
+        * 
+        * @see StringValue#isNull()
+        * 
+        * @param name
+        * @return {...@link StringValue} instance wrapping the parameter value
+        */
+       public StringValue getQueryParameterValue(String name)
+       {
+               QueryParameter parameter = getQueryParameter(name);
+               if (parameter == null)
+               {
+                       return StringValue.valueOf((String)null);
+               }
+               else
+               {
+                       return StringValue.valueOf(parameter.getValue());
+               }
+       }
+
+       /**
+        * Represents a single query parameter
+        * 
+        * @author Matej Knopp
+        */
+       public final static class QueryParameter
+       {
+               private final String name;
+               private final String value;
+
+               /**
+                * Creates new {...@link QueryParameter} instance. The 
<code>name</code>
+                * and <code>value</code> parameters must not be 
<code>null</code>,
+                * though they can be empty strings.
+                * 
+                * @param name
+                *            parameter name
+                * @param value
+                *            parameter value
+                */
+               public QueryParameter(String name, String value)
+               {
+                       Checks.argumentNotNull(name, "name");
+                       Checks.argumentNotNull(value, "value");
+
+                       this.name = name;
+                       this.value = value;
+               }
+
+               /**
+                * Returns query parameter name.
+                * 
+                * @return query parameter name
+                */
+               public String getName()
+               {
+                       return name;
+               }
+
+               /**
+                * Returns query parameter value.
+                * 
+                * @return query parameter value
+                */
+               public String getValue()
+               {
+                       return value;
+               }
+
+               @Override
+               public boolean equals(Object obj)
+               {
+                       if (this == obj)
+                       {
+                               return true;
+                       }
+                       if (obj instanceof QueryParameter == false)
+                       {
+                               return false;
+                       }
+                       QueryParameter rhs = (QueryParameter)obj;
+                       return Objects.equal(getName(), rhs.getName())
+                                       && Objects.equal(getValue(), 
rhs.getValue());
+               }
+
+               @Override
+               public int hashCode()
+               {
+                       return Objects.hashCode(getName(), getValue());
+               }
+
+               @Override
+               public String toString()
+               {
+                       StringBuilder result = new StringBuilder();
+                       result.append(encodeParameter(getName()));
+                       if (!Strings.isEmpty(getValue()))
+                       {
+                               result.append('=');
+                               result.append(encodeParameter(getValue()));
+                       }
+                       return result.toString();
+               }
+       }
+
+       @Override
+       public boolean equals(Object obj)
+       {
+               if (this == obj)
+               {
+                       return true;
+               }
+               if (obj instanceof Url == false)
+               {
+                       return false;
+               }
+               Url rhs = (Url)obj;
+
+               return getSegments().equals(rhs.getSegments())
+                               && 
getQueryParameters().equals(rhs.getQueryParameters());
+       }
+
+       @Override
+       public int hashCode()
+       {
+               return Objects.hashCode(getSegments(), getQueryParameters());
+       }
+
+       private static String encodeSegment(String string)
+       {
+               return WicketURLEncoder.PATH_INSTANCE.encode(string);
+       }
+
+       private static String decodeSegment(String string)
+       {
+               return WicketURLDecoder.PATH_INSTANCE.decode(string);
+       }
+
+       private static String encodeParameter(String string)
+       {
+               return WicketURLEncoder.QUERY_INSTANCE.encode(string);
+       }
+
+       private static String decodeParameter(String string)
+       {
+               return WicketURLDecoder.QUERY_INSTANCE.decode(string);
+       }
+
+       @Override
+       public String toString()
+       {
+               StringBuilder result = new StringBuilder();
+               boolean first = true;
+               for (String s : getSegments())
+               {
+                       if (!first)
+                       {
+                               result.append('/');
+                       }
+                       first = false;
+                       result.append(encodeSegment(s));
+               }
+
+               first = true;
+
+               for (QueryParameter p : getQueryParameters())
+               {
+                       if (first)
+                       {
+                               result.append("?");
+                               first = false;
+                       }
+                       else
+                       {
+                               result.append("&");
+                       }
+                       result.append(p.toString());
+               }
+
+               return result.toString();
+       }
+
+       private static QueryParameter parseQueryParameter(String qp)
+       {
+               if (qp.indexOf('=') == -1)
+               {
+                       return new QueryParameter(decodeParameter(qp), "");
+               }
+               String parts[] = Strings.split(qp, '=');
+               if (parts.length == 0)
+               {
+                       return new QueryParameter("", "");
+               }
+               else if (parts.length == 1)
+               {
+                       return new QueryParameter("", 
decodeParameter(parts[0]));
+               }
+               else
+               {
+                       return new QueryParameter(decodeParameter(parts[0]), 
decodeParameter(parts[1]));
+               }
+       }
+
+       /**
+        * Parses the given URL string.
+        * 
+        * @param url
+        * @return Url object
+        */
+       public static Url parse(String url)
+       {
+               Checks.argumentNotNull(url, "url");
+
+               Url result = new Url();
+
+               String segments;
+               String query;
+
+               int qIndex = url.indexOf('?');
+
+               if (qIndex == -1)
+               {
+                       segments = url;
+                       query = "";
+               }
+               else
+               {
+                       segments = url.substring(0, qIndex);
+                       query = url.substring(qIndex + 1);
+               }
+
+               if (segments.length() > 0)
+               {
+
+                       boolean removeLast = false;
+                       if (segments.endsWith("/"))
+                       {
+                               // we need to append something and remove it 
after splitting
+                               // because otherwise the
+                               // trailing slashes will be lost
+                               segments += "/x";
+                               removeLast = true;
+                       }
+
+                       String segmentArray[] = Strings.split(segments, '/');
+
+                       if (removeLast)
+                       {
+                               segmentArray[segmentArray.length - 1] = null;
+                       }
+
+                       for (String s : segmentArray)
+                       {
+                               if (s != null)
+                               {
+                                       result.segments.add(decodeSegment(s));
+                               }
+                       }
+               }
+
+               if (query.length() > 0)
+               {
+                       String queryArray[] = Strings.split(query, '&');
+                       for (String s : queryArray)
+                       {
+                               result.parameters.add(parseQueryParameter(s));
+                       }
+               }
 
-        return result;
-    };
+               return result;
+       };
 }


Reply via email to