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.rest.util; 014 015import static org.apache.juneau.collections.JsonMap.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018 019import java.util.*; 020 021/** 022 * Represents a parsed URL path-info string. 023 * 024 * <h5 class='section'>See Also:</h5><ul> 025 * </ul> 026 */ 027public class UrlPath { 028 029 final String[] parts; 030 final String path; 031 032 /** 033 * Creates a new parsed {@link UrlPath} object from the specified string. 034 * 035 * @param path The path to create. Must be <jk>null</jk> or or start with '/' per HttpServletRequest.getPathInfo(). 036 * @return A new {@link UrlPath} object. 037 */ 038 public static UrlPath of(String path) { 039 if (path != null && ! path.startsWith("/")) 040 throw new RuntimeException("Invalid path specified. Must be null or start with '/' per HttpServletRequest.getPathInfo()."); 041 return new UrlPath(path); 042 } 043 044 /** 045 * Constructor. 046 * 047 * @param path The path. 048 */ 049 UrlPath(String path) { 050 this.path = path; 051 parts = path == null ? new String[0] : split(path.substring(1), '/'); 052 for (int i = 0; i < parts.length; i++) 053 parts[i] = urlDecode(parts[i]); 054 } 055 056 /** 057 * Returns the path parts. 058 * 059 * @return The path parts. 060 */ 061 public String[] getParts() { 062 return parts; 063 } 064 065 066 /** 067 * Returns the filename portion of the path if there is one. 068 * 069 * <p> 070 * For example, given the path <js>"/foo/bar.txt"</js>, this returns <js>"bar.txt"</js>. 071 * 072 * @return The filename portion of the path, or <jk>null</jk> if the path doesn't match a file name. 073 */ 074 public Optional<String> getFileName() { 075 if (parts.length == 0) 076 return empty(); 077 String p = parts[parts.length-1]; 078 if (p.indexOf('.') == -1) 079 return empty(); 080 return optional(p); 081 } 082 083 /** 084 * Returns the raw path passed into this object. 085 * 086 * @return The raw path passed into this object. 087 */ 088 public String getPath() { 089 return path; 090 } 091 092 /** 093 * Returns <jk>true</jk> if this path ends with a slash. 094 * 095 * @return <jk>true</jk> if this path ends with a slash. 096 */ 097 public boolean isTrailingSlash() { 098 return path != null && path.endsWith("/"); 099 } 100 101 @Override /* Object */ 102 public String toString() { 103 return filteredMap() 104 .append("raw", path) 105 .append("parts", parts) 106 .asReadableString(); 107 } 108}