xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/util/UriUtils.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1fb1fd46dSChris Fraire /*
2fb1fd46dSChris Fraire  * CDDL HEADER START
3fb1fd46dSChris Fraire  *
4fb1fd46dSChris Fraire  * The contents of this file are subject to the terms of the
5fb1fd46dSChris Fraire  * Common Development and Distribution License (the "License").
6fb1fd46dSChris Fraire  * You may not use this file except in compliance with the License.
7fb1fd46dSChris Fraire  *
8fb1fd46dSChris Fraire  * See LICENSE.txt included in this distribution for the specific
9fb1fd46dSChris Fraire  * language governing permissions and limitations under the License.
10fb1fd46dSChris Fraire  *
11fb1fd46dSChris Fraire  * When distributing Covered Code, include this CDDL HEADER in each
12fb1fd46dSChris Fraire  * file and include the License file at LICENSE.txt.
13fb1fd46dSChris Fraire  * If applicable, add the following below this CDDL HEADER, with the
14fb1fd46dSChris Fraire  * fields enclosed by brackets "[]" replaced with your own identifying
15fb1fd46dSChris Fraire  * information: Portions Copyright [yyyy] [name of copyright owner]
16fb1fd46dSChris Fraire  *
17fb1fd46dSChris Fraire  * CDDL HEADER END
18fb1fd46dSChris Fraire  */
19fb1fd46dSChris Fraire 
20fb1fd46dSChris Fraire /*
21*5d9f3aa0SAdam Hornáček  * Copyright (c) 2017, 2019, Chris Fraire <cfraire@me.com>.
22fb1fd46dSChris Fraire  */
23fb1fd46dSChris Fraire package org.opengrok.indexer.util;
24fb1fd46dSChris Fraire 
25fb1fd46dSChris Fraire import java.util.regex.Pattern;
26fb1fd46dSChris Fraire 
27fb1fd46dSChris Fraire /**
28fb1fd46dSChris Fraire  * Represents a container for utility methods concerned with URIs.
29fb1fd46dSChris Fraire  */
30fb1fd46dSChris Fraire public class UriUtils {
31fb1fd46dSChris Fraire 
32fb1fd46dSChris Fraire     /**
33fb1fd46dSChris Fraire      * Represents the immutable return value of
34fb1fd46dSChris Fraire      * {@link #trimUri(String, boolean, Pattern)}.
35fb1fd46dSChris Fraire      */
36fb1fd46dSChris Fraire     public static final class TrimUriResult {
37fb1fd46dSChris Fraire         private final String uri;
38fb1fd46dSChris Fraire         private final int pushBackCount;
39fb1fd46dSChris Fraire 
TrimUriResult(String uri, int pushBackCount)40fb1fd46dSChris Fraire         TrimUriResult(String uri, int pushBackCount) {
41fb1fd46dSChris Fraire             this.uri = uri;
42fb1fd46dSChris Fraire             this.pushBackCount = pushBackCount;
43fb1fd46dSChris Fraire         }
44fb1fd46dSChris Fraire 
getUri()45fb1fd46dSChris Fraire         public String getUri() {
46fb1fd46dSChris Fraire             return uri;
47fb1fd46dSChris Fraire         }
48fb1fd46dSChris Fraire 
getPushBackCount()49fb1fd46dSChris Fraire         public int getPushBackCount() {
50fb1fd46dSChris Fraire             return pushBackCount;
51fb1fd46dSChris Fraire         }
52fb1fd46dSChris Fraire     }
53fb1fd46dSChris Fraire 
54fb1fd46dSChris Fraire     /**
55fb1fd46dSChris Fraire      * Trims a URI, specifying whether to enlist the
56fb1fd46dSChris Fraire      * {@link StringUtils#countURIEndingPushback(String)} algorithm or the
57fb1fd46dSChris Fraire      * {@link StringUtils#countPushback(String, Pattern)} or both.
58fb1fd46dSChris Fraire      * <p>
59fb1fd46dSChris Fraire      * If the pushback count is equal to the length of {@code url}, then the
60fb1fd46dSChris Fraire      * pushback is set to zero -- in order to avoid a never-ending lexical loop.
61fb1fd46dSChris Fraire      *
62fb1fd46dSChris Fraire      * @param uri the URI string
63fb1fd46dSChris Fraire      * @param shouldCheckEnding a value indicating whether to call
64fb1fd46dSChris Fraire      * {@link StringUtils#countURIEndingPushback(String)}
65fb1fd46dSChris Fraire      * @param collateralCapture optional pattern to call with
66fb1fd46dSChris Fraire      * {@link StringUtils#countPushback(String, Pattern)}
67fb1fd46dSChris Fraire      * @return a defined instance
68fb1fd46dSChris Fraire      */
trimUri(String uri, boolean shouldCheckEnding, Pattern collateralCapture)69fb1fd46dSChris Fraire     public static TrimUriResult trimUri(String uri, boolean shouldCheckEnding,
70fb1fd46dSChris Fraire             Pattern collateralCapture) {
71fb1fd46dSChris Fraire 
72fb1fd46dSChris Fraire         int n = 0;
73fb1fd46dSChris Fraire         while (true) {
74fb1fd46dSChris Fraire             /*
75fb1fd46dSChris Fraire              * An ending-pushback could be present before a collateral capture,
76fb1fd46dSChris Fraire              * so detect both in a loop (on a shrinking `url') until no more
77fb1fd46dSChris Fraire              * shrinking should occur.
78fb1fd46dSChris Fraire              */
79fb1fd46dSChris Fraire 
80fb1fd46dSChris Fraire             int subN = 0;
81fb1fd46dSChris Fraire             if (shouldCheckEnding) {
82fb1fd46dSChris Fraire                 subN = StringUtils.countURIEndingPushback(uri);
83fb1fd46dSChris Fraire             }
84fb1fd46dSChris Fraire             int ccn = StringUtils.countPushback(uri, collateralCapture);
85fb1fd46dSChris Fraire             if (ccn > subN) {
86fb1fd46dSChris Fraire                 subN = ccn;
87fb1fd46dSChris Fraire             }
88fb1fd46dSChris Fraire 
89fb1fd46dSChris Fraire             // Increment if positive, but not if equal to the current length.
90fb1fd46dSChris Fraire             if (subN > 0 && subN < uri.length()) {
91fb1fd46dSChris Fraire                 uri = uri.substring(0, uri.length() - subN);
92fb1fd46dSChris Fraire                 n += subN;
93fb1fd46dSChris Fraire             } else {
94fb1fd46dSChris Fraire                 break;
95fb1fd46dSChris Fraire             }
96fb1fd46dSChris Fraire         }
97fb1fd46dSChris Fraire         return new TrimUriResult(uri, n);
98fb1fd46dSChris Fraire     }
99fb1fd46dSChris Fraire 
100fb1fd46dSChris Fraire     /** Private to enforce static. */
UriUtils()101fb1fd46dSChris Fraire     private UriUtils() {
102fb1fd46dSChris Fraire     }
103fb1fd46dSChris Fraire }
104