99b6e629415f5aa693e04320968355e78156979e
[idea/community.git] / platform / platform-impl / src / com / intellij / util / UrlImpl.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.util;
17
18 import com.intellij.openapi.util.text.StringUtil;
19 import com.intellij.util.io.URLUtil;
20 import org.jetbrains.annotations.NotNull;
21 import org.jetbrains.annotations.Nullable;
22
23 public final class UrlImpl implements Url {
24   private final String scheme;
25   private final String authority;
26
27   private final String path;
28   private String decodedPath;
29
30   private final String parameters;
31
32   private String externalForm;
33   private UrlImpl withoutParameters;
34
35   public UrlImpl(@NotNull String path) {
36     this(null, null, path, null);
37   }
38
39   UrlImpl(@NotNull String scheme, @Nullable String authority, @Nullable String path) {
40     this(scheme, authority, path, null);
41   }
42
43   public UrlImpl(@Nullable String scheme, @Nullable String authority, @Nullable String path, @Nullable String parameters) {
44     this.scheme = scheme;
45     this.authority = authority;
46     this.path = StringUtil.notNullize(path);
47     this.parameters = StringUtil.nullize(parameters);
48   }
49
50   @NotNull
51   @Override
52   public String getPath() {
53     if (decodedPath == null) {
54       decodedPath = URLUtil.unescapePercentSequences(path);
55     }
56     return decodedPath;
57   }
58
59   @Nullable
60   @Override
61   public String getScheme() {
62     return scheme;
63   }
64
65   @Override
66   @Nullable
67   public String getAuthority() {
68     return authority;
69   }
70
71   @Override
72   public boolean isInLocalFileSystem() {
73     return URLUtil.FILE_PROTOCOL.equals(scheme);
74   }
75
76   @Nullable
77   @Override
78   public String getParameters() {
79     return parameters;
80   }
81
82   @Override
83   public String toDecodedForm() {
84     StringBuilder builder = new StringBuilder();
85     if (scheme != null) {
86       builder.append(scheme);
87       if (authority == null) {
88         builder.append(':');
89       }
90       else {
91         builder.append(URLUtil.SCHEME_SEPARATOR);
92       }
93
94       if (authority != null) {
95         builder.append(authority);
96       }
97     }
98     builder.append(getPath());
99     if (parameters != null) {
100       builder.append(parameters);
101     }
102     return builder.toString();
103   }
104
105   @Override
106   @NotNull
107   public String toExternalForm() {
108     if (externalForm != null) {
109       return externalForm;
110     }
111
112     // relative path - special url, encoding is not required
113     // authority is null in case of URI
114     if ((authority == null || (!path.isEmpty() && path.charAt(0) != '/')) && !isInLocalFileSystem()) {
115       return toDecodedForm();
116     }
117
118     String result = Urls.toUriWithoutParameters(this).toASCIIString();
119     if (parameters != null) {
120       result += parameters;
121     }
122     externalForm = result;
123     return result;
124   }
125
126   @Override
127   @NotNull
128   public Url trimParameters() {
129     if (parameters == null) {
130       return this;
131     }
132     else if (withoutParameters == null) {
133       withoutParameters = new UrlImpl(scheme, authority, path, null);
134     }
135     return withoutParameters;
136   }
137
138   @Override
139   public String toString() {
140     return toExternalForm();
141   }
142
143   @Override
144   public boolean equals(Object o) {
145     if (this == o) {
146       return true;
147     }
148     if (!(o instanceof UrlImpl)) {
149       return false;
150     }
151
152     UrlImpl url = (UrlImpl)o;
153     return StringUtil.equals(scheme, url.scheme) && StringUtil.equals(authority, url.authority) && getPath().equals(url.getPath()) && StringUtil.equals(parameters, url.parameters);
154   }
155
156   @Override
157   public boolean equalsIgnoreCase(@Nullable Url o) {
158     if (this == o) {
159       return true;
160     }
161     if (!(o instanceof UrlImpl)) {
162       return false;
163     }
164
165     UrlImpl url = (UrlImpl)o;
166     return StringUtil.equalsIgnoreCase(scheme, url.scheme) &&
167            StringUtil.equalsIgnoreCase(authority, url.authority) &&
168            getPath().equalsIgnoreCase(url.getPath()) &&
169            StringUtil.equalsIgnoreCase(parameters, url.parameters);
170   }
171
172   @Override
173   public boolean equalsIgnoreParameters(@Nullable Url url) {
174     return url != null && equals(url.trimParameters());
175   }
176
177   private int computeHashCode(boolean caseSensitive) {
178     int result = stringHashCode(scheme, caseSensitive);
179     result = 31 * result + stringHashCode(authority, caseSensitive);
180     result = 31 * result + stringHashCode(getPath(), caseSensitive);
181     result = 31 * result + stringHashCode(parameters, caseSensitive);
182     return result;
183   }
184
185   private static int stringHashCode(@Nullable CharSequence string, boolean caseSensitive) {
186     return string == null ? 0 : (caseSensitive ? string.hashCode() : StringUtil.stringHashCodeInsensitive(string));
187   }
188
189   @Override
190   public int hashCode() {
191     return computeHashCode(true);
192   }
193
194   @Override
195   public int hashCodeCaseInsensitive() {
196     return computeHashCode(false);
197   }
198 }