1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.catalina.util;
18
19 import java.util.Locale;
20
21 /**
22 * Utility class to manage context names so there is one place where the
23 * conversions between baseName, path and version take place.
24 */
25 public final class ContextName {
26 public static final String ROOT_NAME = "ROOT";
27 private static final String VERSION_MARKER = "##";
28 private static final String FWD_SLASH_REPLACEMENT = "#";
29
30 private final String baseName;
31 private final String path;
32 private final String version;
33 private final String name;
34
35
36 /**
37 * Creates an instance from a context name, display name, base name,
38 * directory name, WAR name or context.xml name.
39 *
40 * @param name The name to use as the basis for this object
41 * @param stripFileExtension If a .war or .xml file extension is present
42 * at the end of the provided name should it be
43 * removed?
44 */
45 public ContextName(String name, boolean stripFileExtension) {
46
47 String tmp1 = name;
48
49 // Convert Context names and display names to base names
50
51 // Strip off any leading "/"
52 if (tmp1.startsWith("/")) {
53 tmp1 = tmp1.substring(1);
54 }
55
56 // Replace any remaining /
57 tmp1 = tmp1.replaceAll("/", FWD_SLASH_REPLACEMENT);
58
59 // Insert the ROOT name if required
60 if (tmp1.startsWith(VERSION_MARKER) || "".equals(tmp1)) {
61 tmp1 = ROOT_NAME + tmp1;
62 }
63
64 // Remove any file extensions
65 if (stripFileExtension &&
66 (tmp1.toLowerCase(Locale.ENGLISH).endsWith(".war") ||
67 tmp1.toLowerCase(Locale.ENGLISH).endsWith(".xml"))) {
68 tmp1 = tmp1.substring(0, tmp1.length() -4);
69 }
70
71 baseName = tmp1;
72
73 String tmp2;
74 // Extract version number
75 int versionIndex = baseName.indexOf(VERSION_MARKER);
76 if (versionIndex > -1) {
77 version = baseName.substring(versionIndex + 2);
78 tmp2 = baseName.substring(0, versionIndex);
79 } else {
80 version = "";
81 tmp2 = baseName;
82 }
83
84 if (ROOT_NAME.equals(tmp2)) {
85 path = "";
86 } else {
87 path = "/" + tmp2.replaceAll(FWD_SLASH_REPLACEMENT, "/");
88 }
89
90 if (versionIndex > -1) {
91 this.name = path + VERSION_MARKER + version;
92 } else {
93 this.name = path;
94 }
95 }
96
97 /**
98 * Construct an instance from a path and version.
99 *
100 * @param path Context path to use
101 * @param version Context version to use
102 */
103 public ContextName(String path, String version) {
104 // Path should never be null, '/' or '/ROOT'
105 if (path == null || "/".equals(path) || "/ROOT".equals(path)) {
106 this.path = "";
107 } else {
108 this.path = path;
109 }
110
111 // Version should never be null
112 if (version == null) {
113 this.version = "";
114 } else {
115 this.version = version;
116 }
117
118 // Name is path + version
119 if ("".equals(this.version)) {
120 name = this.path;
121 } else {
122 name = this.path + VERSION_MARKER + this.version;
123 }
124
125 // Base name is converted path + version
126 StringBuilder tmp = new StringBuilder();
127 if ("".equals(this.path)) {
128 tmp.append(ROOT_NAME);
129 } else {
130 tmp.append(this.path.substring(1).replaceAll("/",
131 FWD_SLASH_REPLACEMENT));
132 }
133 if (this.version.length() > 0) {
134 tmp.append(VERSION_MARKER);
135 tmp.append(this.version);
136 }
137 this.baseName = tmp.toString();
138 }
139
140 public String getBaseName() {
141 return baseName;
142 }
143
144 public String getPath() {
145 return path;
146 }
147
148 public String getVersion() {
149 return version;
150 }
151
152 public String getName() {
153 return name;
154 }
155
156 public String getDisplayName() {
157 StringBuilder tmp = new StringBuilder();
158 if ("".equals(path)) {
159 tmp.append('/');
160 } else {
161 tmp.append(path);
162 }
163
164 if (!"".equals(version)) {
165 tmp.append(VERSION_MARKER);
166 tmp.append(version);
167 }
168
169 return tmp.toString();
170 }
171
172 @Override
173 public String toString() {
174 return getDisplayName();
175 }
176
177
178 /**
179 * Extract the final component of the given path which is assumed to be a
180 * base name and generate a {@link ContextName} from that base name.
181 *
182 * @param path The path that ends in a base name
183 *
184 * @return the {@link ContextName} generated from the given base name
185 */
186 public static ContextName extractFromPath(String path) {
187 // Convert '\' to '/'
188 path = path.replaceAll("\\\\", "/");
189 // Remove trailing '/'. Use while just in case a value ends in ///
190 while (path.endsWith("/")) {
191 path = path.substring(0, path.length() - 1);
192 }
193
194 int lastSegment = path.lastIndexOf('/');
195 if (lastSegment > 0) {
196 path = path.substring(lastSegment + 1);
197 }
198
199 return new ContextName(path, true);
200 }
201 }
202