001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import static org.apache.juneau.internal.StringUtils.*; 016 017import org.apache.juneau.annotation.*; 018import org.apache.juneau.collections.*; 019import org.apache.juneau.json.*; 020import org.apache.juneau.parser.*; 021 022/** 023 * Represents a URL broken into authority/context-root/servlet-path/path-info parts. 024 * 025 * <p> 026 * A typical request against a URL takes the following form: 027 * <p class='bcode w800'> 028 * http://host:port/context-root/servlet-path/path-info 029 * | authority | context | resource | path | 030 * +--------------------------------------------------+ 031 * </p> 032 * 033 * <p> 034 * This class allows you to convert URL strings to absolute (e.g. <js>"http://host:port/foo/bar"</js>) or root-relative 035 * (e.g. <js>"/foo/bar"</js>) URLs. 036 */ 037@Bean 038public class UriContext { 039 040 /** 041 * Default URI context. 042 * 043 * <p> 044 * No information about authority, servlet-root, context-root, or path-info is known. 045 */ 046 public static final UriContext DEFAULT = new UriContext(); 047 048 @SuppressWarnings("javadoc") 049 public final String authority, contextRoot, servletPath, pathInfo, parentPath; 050 051 // Lazy-initialized fields. 052 private String aContextRoot, rContextRoot, aServletPath, rResource, aPathInfo, rPath; 053 054 /** 055 * Convenience creator. 056 * 057 * @param authority 058 * The authority portion of URL (e.g. <js>"http://hostname:port"</js>) 059 * @param contextRoot 060 * The context root of the application (e.g. <js>"/context-root"</js>, or <js>"context-root"</js>) 061 * @param servletPath 062 * The servlet path (e.g. <js>"/servlet-path"</js>, or <js>"servlet-path"</js>) 063 * @param pathInfo 064 * The path info (e.g. <js>"/path-info"</js>, or <js>"path-info"</js>) 065 * @return A new {@link UriContext} object. 066 */ 067 public static UriContext of(String authority, String contextRoot, String servletPath, String pathInfo) { 068 return new UriContext(authority, contextRoot, servletPath, pathInfo); 069 } 070 071 /** 072 * Constructor. 073 * 074 * <p> 075 * Leading and trailing slashes are trimmed of all parameters. 076 * 077 * <p> 078 * Any parameter can be <jk>null</jk>. Blanks and nulls are equivalent. 079 * 080 * @param authority 081 * The authority portion of URL (e.g. <js>"http://hostname:port"</js>) 082 * @param contextRoot 083 * The context root of the application (e.g. <js>"/context-root"</js>, or <js>"context-root"</js>) 084 * @param servletPath 085 * The servlet path (e.g. <js>"/servlet-path"</js>, or <js>"servlet-path"</js>) 086 * @param pathInfo 087 * The path info (e.g. <js>"/path-info"</js>, or <js>"path-info"</js>) 088 */ 089 @Beanc 090 public UriContext(@Name("authority") String authority, @Name("contextRoot") String contextRoot, @Name("servletPath") String servletPath, @Name("pathInfo") String pathInfo) { 091 this.authority = nullIfEmpty(trimSlashes(authority)); 092 this.contextRoot = nullIfEmpty(trimSlashes(contextRoot)); 093 this.servletPath = nullIfEmpty(trimSlashes(servletPath)); 094 this.pathInfo = nullIfEmpty(trimSlashes(pathInfo)); 095 this.parentPath = this.pathInfo == null || this.pathInfo.indexOf('/') == -1 ? null 096 : this.pathInfo.substring(0, this.pathInfo.lastIndexOf('/')); 097 } 098 099 /** 100 * Default constructor. 101 * 102 * <p> 103 * All <jk>null</jk> values. 104 */ 105 public UriContext() { 106 this(null, null, null, null); 107 } 108 109 /** 110 * String constructor. 111 * 112 * <p> 113 * Input string is a JSON object with the following format: 114 * <js>{authority:'xxx',contextRoot:'xxx',servletPath:'xxx',pathInfo:'xxx'}</js> 115 * 116 * @param s 117 * The input string. 118 * <br>Example: <js>{authority:'http://localhost:10000',contextRoot:'/myContext',servletPath:'/myServlet',pathInfo:'/foo'}</js> 119 * @throws ParseException 120 * If input string is not a valid JSON object. 121 */ 122 public UriContext(String s) throws ParseException { 123 OMap m = OMap.ofJson(s); 124 this.authority = nullIfEmpty(trimSlashes(m.getString("authority"))); 125 this.contextRoot = nullIfEmpty(trimSlashes(m.getString("contextRoot"))); 126 this.servletPath = nullIfEmpty(trimSlashes(m.getString("servletPath"))); 127 this.pathInfo = nullIfEmpty(trimSlashes(m.getString("pathInfo"))); 128 this.parentPath = this.pathInfo == null || this.pathInfo.indexOf('/') == -1 ? null 129 : this.pathInfo.substring(0, this.pathInfo.lastIndexOf('/')); 130 } 131 132 /** 133 * Returns the absolute URI of just the authority portion of this URI context. 134 * 135 * <p> 136 * Example: <js>"http://hostname:port"</js> 137 * 138 * <p> 139 * If the authority is null/empty, returns <js>"/"</js>. 140 * 141 * @return 142 * The absolute URI of just the authority portion of this URI context. 143 * Never <jk>null</jk>. 144 */ 145 public String getAbsoluteAuthority() { 146 return authority == null ? "/" : authority; 147 } 148 149 /** 150 * Returns the absolute URI of the context-root portion of this URI context. 151 * 152 * <p> 153 * Example: <js>"http://hostname:port/context-root"</js> 154 * 155 * @return 156 * The absolute URI of the context-root portion of this URI context. 157 * Never <jk>null</jk>. 158 */ 159 public String getAbsoluteContextRoot() { 160 if (aContextRoot == null) { 161 if (authority == null) 162 aContextRoot = getRootRelativeContextRoot(); 163 else 164 aContextRoot = ( 165 contextRoot == null 166 ? authority 167 : (authority + '/' + contextRoot) 168 ); 169 } 170 return aContextRoot; 171 } 172 173 /** 174 * Returns the root-relative URI of the context portion of this URI context. 175 * 176 * <p> 177 * Example: <js>"/context-root"</js> 178 * 179 * @return 180 * The root-relative URI of the context portion of this URI context. 181 * Never <jk>null</jk>. 182 */ 183 public String getRootRelativeContextRoot() { 184 if (rContextRoot == null) 185 rContextRoot = contextRoot == null ? "/" : ('/' + contextRoot); 186 return rContextRoot; 187 } 188 189 /** 190 * Returns the absolute URI of the resource portion of this URI context. 191 * 192 * <p> 193 * Example: <js>"http://hostname:port/context-root/servlet-path"</js> 194 * 195 * @return 196 * The absolute URI of the resource portion of this URI context. 197 * Never <jk>null</jk>. 198 */ 199 public String getAbsoluteServletPath() { 200 if (aServletPath == null) { 201 if (authority == null) 202 aServletPath = getRootRelativeServletPath(); 203 else { 204 if (contextRoot == null) 205 aServletPath = ( 206 servletPath == null 207 ? authority 208 : authority + '/' + servletPath 209 ); 210 else 211 aServletPath = ( 212 servletPath == null 213 ? (authority + '/' + contextRoot) 214 : (authority + '/' + contextRoot + '/' + servletPath) 215 ); 216 } 217 } 218 return aServletPath; 219 } 220 221 /** 222 * Returns the root-relative URI of the resource portion of this URI context. 223 * 224 * <p> 225 * Example: <js>"/context-root/servlet-path"</js> 226 * 227 * @return 228 * The root-relative URI of the resource portion of this URI context. 229 * Never <jk>null</jk>. 230 */ 231 public String getRootRelativeServletPath() { 232 if (rResource == null) { 233 if (contextRoot == null) 234 rResource = ( 235 servletPath == null 236 ? "/" 237 : ('/' + servletPath) 238 ); 239 else 240 rResource = ( 241 servletPath == null 242 ? ('/' + contextRoot) 243 : ('/' + contextRoot + '/' + servletPath) 244 ); 245 } 246 return rResource; 247 } 248 249 /** 250 * Returns the parent of the URL returned by {@link #getAbsoluteServletPath()}. 251 * 252 * @return The parent of the URL returned by {@link #getAbsoluteServletPath()}. 253 */ 254 public String getAbsoluteServletPathParent() { 255 return getParent(getAbsoluteServletPath()); 256 } 257 258 /** 259 * Returns the parent of the URL returned by {@link #getRootRelativeServletPath()}. 260 * 261 * @return The parent of the URL returned by {@link #getRootRelativeServletPath()}. 262 */ 263 public String getRootRelativeServletPathParent() { 264 return getParent(getRootRelativeServletPath()); 265 } 266 267 /** 268 * Returns the absolute URI of the path portion of this URI context. 269 * 270 * <p> 271 * Example: <js>"http://hostname:port/context-root/servlet-path/path-info"</js> 272 * 273 * @return 274 * The absolute URI of the path portion of this URI context. 275 * Never <jk>null</jk>. 276 */ 277 public String getAbsolutePathInfo() { 278 if (aPathInfo == null) { 279 if (authority == null) 280 aPathInfo = getRootRelativePathInfo(); 281 else { 282 if (contextRoot == null) { 283 if (servletPath == null) 284 aPathInfo = ( 285 pathInfo == null 286 ? authority : (authority + '/' + pathInfo) 287 ); 288 else 289 aPathInfo = ( 290 pathInfo == null 291 ? (authority + '/' + servletPath) 292 : (authority + '/' + servletPath + '/' + pathInfo) 293 ); 294 } else { 295 if (servletPath == null) 296 aPathInfo = ( 297 pathInfo == null 298 ? authority + '/' + contextRoot 299 : (authority + '/' + contextRoot + '/' + pathInfo) 300 ); 301 else 302 aPathInfo = ( 303 pathInfo == null 304 ? (authority + '/' + contextRoot + '/' + servletPath) 305 : (authority + '/' + contextRoot + '/' + servletPath + '/' + pathInfo) 306 ); 307 } 308 } 309 } 310 return aPathInfo; 311 } 312 313 /** 314 * Returns the root-relative URI of the path portion of this URI context. 315 * 316 * <p> 317 * Example: <js>"/context-root/servlet-path/path-info"</js> 318 * 319 * @return 320 * The root-relative URI of the path portion of this URI context. 321 * Never <jk>null</jk>. 322 */ 323 public String getRootRelativePathInfo() { 324 if (rPath == null) { 325 if (contextRoot == null) { 326 if (servletPath == null) 327 rPath = ( 328 pathInfo == null 329 ? "/" 330 : ('/' + pathInfo) 331 ); 332 else 333 rPath = ( 334 pathInfo == null 335 ? ('/' + servletPath) 336 : ('/' + servletPath + '/' + pathInfo) 337 ); 338 } else { 339 if (servletPath == null) 340 rPath = ( 341 pathInfo == null 342 ? ('/' + contextRoot) 343 : ('/' + contextRoot + '/' + pathInfo) 344 ); 345 else 346 rPath = ( 347 pathInfo == null 348 ? ('/' + contextRoot + '/' + servletPath) 349 : ('/' + contextRoot + '/' + servletPath + '/' + pathInfo) 350 ); 351 } 352 } 353 return rPath; 354 } 355 356 /** 357 * Returns the parent of the URL returned by {@link #getAbsolutePathInfo()}. 358 * 359 * @return The parent of the URL returned by {@link #getAbsolutePathInfo()}. 360 */ 361 public String getAbsolutePathInfoParent() { 362 return getParent(getAbsolutePathInfo()); 363 } 364 365 /** 366 * Returns the parent of the URL returned by {@link #getRootRelativePathInfo()}. 367 * 368 * @return The parent of the URL returned by {@link #getRootRelativePathInfo()}. 369 */ 370 public String getRootRelativePathInfoParent() { 371 return getParent(getRootRelativePathInfo()); 372 } 373 374 private static String getParent(String uri) { 375 int i = uri.lastIndexOf('/'); 376 if (i <= 1) 377 return "/"; 378 return uri.substring(0, i); 379 } 380 381 @Override /* Object */ 382 public String toString() { 383 return SimpleJsonSerializer.DEFAULT.toString(this); 384 } 385}