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