001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone;
008:
009: /**
010: * Encapsulates the parsing of URL patterns, as well as the mapping of a
011: * url pattern to a servlet instance
012: *
013: * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
014: * @version $Id: Mapping.java,v 1.9 2007/04/23 02:55:35 rickknowles Exp $
015: */
016: public class Mapping implements java.util.Comparator {
017: public static final int EXACT_PATTERN = 1;
018: public static final int FOLDER_PATTERN = 2;
019: public static final int EXTENSION_PATTERN = 3;
020: public static final int DEFAULT_SERVLET = 4;
021:
022: public static final String STAR = "*";
023: public static final String SLASH = "/";
024:
025: private String urlPattern;
026: private String linkName; // used to map filters to a specific servlet by
027: // name
028: private String mappedTo;
029: private int patternType;
030: private boolean isPatternFirst; // ie is this a blah* pattern, not *blah
031:
032: // (extensions only)
033:
034: protected Mapping(String mappedTo) {
035: this .mappedTo = mappedTo;
036: }
037:
038: /**
039: * Factory constructor method - this parses the url pattern into pieces we can use to match
040: * against incoming URLs.
041: */
042: public static Mapping createFromURL(String mappedTo, String pattern) {
043: if ((pattern == null) || (mappedTo == null))
044: throw new WinstoneException(Launcher.RESOURCES.getString(
045: "Mapping.InvalidMount", new String[] { mappedTo,
046: pattern }));
047:
048: // Compatibility hacks - add a leading slash if one is not found and not
049: // an extension mapping
050: if (!pattern.equals("") && !pattern.startsWith(STAR)
051: && !pattern.startsWith(SLASH)) {
052: pattern = SLASH + pattern;
053: } else if (pattern.equals(STAR)) {
054: Logger.log(Logger.WARNING, Launcher.RESOURCES,
055: "Mapping.RewritingStarMount");
056: pattern = SLASH + STAR;
057: }
058:
059: Mapping me = new Mapping(mappedTo);
060:
061: int firstStarPos = pattern.indexOf(STAR);
062: int lastStarPos = pattern.lastIndexOf(STAR);
063: int patternLength = pattern.length();
064:
065: // check for default servlet, ie mapping = exactly /
066: if (pattern.equals(SLASH)) {
067: me.urlPattern = "";
068: me.patternType = DEFAULT_SERVLET;
069: }
070:
071: else if (firstStarPos == -1) {
072: me.urlPattern = pattern;
073: me.patternType = EXACT_PATTERN;
074: }
075:
076: // > 1 star = error
077: else if (firstStarPos != lastStarPos)
078: throw new WinstoneException(Launcher.RESOURCES.getString(
079: "Mapping.InvalidMount", new String[] { mappedTo,
080: pattern }));
081:
082: // check for folder style mapping (ends in /*)
083: else if (pattern.indexOf(SLASH + STAR) == (patternLength - (SLASH + STAR)
084: .length())) {
085: me.urlPattern = pattern.substring(0, pattern.length()
086: - (SLASH + STAR).length());
087: me.patternType = FOLDER_PATTERN;
088: }
089:
090: // check for non-extension match
091: else if (pattern.indexOf(SLASH) != -1)
092: throw new WinstoneException(Launcher.RESOURCES.getString(
093: "Mapping.InvalidMount", new String[] { mappedTo,
094: pattern }));
095:
096: // check for extension match at the beginning (eg *blah)
097: else if (firstStarPos == 0) {
098: me.urlPattern = pattern.substring(STAR.length());
099: me.patternType = EXTENSION_PATTERN;
100: me.isPatternFirst = false;
101: }
102: // check for extension match at the end (eg blah*)
103: else if (firstStarPos == (patternLength - STAR.length())) {
104: me.urlPattern = pattern.substring(0, patternLength
105: - STAR.length());
106: me.patternType = EXTENSION_PATTERN;
107: me.isPatternFirst = true;
108: } else
109: throw new WinstoneException(Launcher.RESOURCES.getString(
110: "Mapping.InvalidMount", new String[] { mappedTo,
111: pattern }));
112:
113: Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
114: "Mapping.MappedPattern", new String[] { mappedTo,
115: pattern });
116: return me;
117: }
118:
119: /**
120: * Factory constructor method - this turns a servlet name into a mapping element
121: */
122: public static Mapping createFromLink(String mappedTo,
123: String linkName) {
124: if ((linkName == null) || (mappedTo == null))
125: throw new WinstoneException(Launcher.RESOURCES.getString(
126: "Mapping.InvalidLink", new String[] { mappedTo,
127: linkName }));
128:
129: Mapping me = new Mapping(mappedTo);
130: me.linkName = linkName;
131: return me;
132: }
133:
134: public int getPatternType() {
135: return this .patternType;
136: }
137:
138: public String getUrlPattern() {
139: return this .urlPattern;
140: }
141:
142: public String getMappedTo() {
143: return this .mappedTo;
144: }
145:
146: public String getLinkName() {
147: return this .linkName;
148: }
149:
150: /**
151: * Try to match this pattern against the incoming url
152: *
153: * @param inputPattern The URL we want to check for a match
154: * @param servletPath An empty stringbuffer for the servletPath of a successful match
155: * @param pathInfo An empty stringbuffer for the pathInfo of a successful match
156: * @return true if the match is successful
157: */
158: public boolean match(String inputPattern, StringBuffer servletPath,
159: StringBuffer pathInfo) {
160: switch (this .patternType) {
161: case FOLDER_PATTERN:
162: if (inputPattern.startsWith(this .urlPattern + '/')
163: || inputPattern.equals(this .urlPattern)) {
164: if (servletPath != null)
165: servletPath.append(WinstoneRequest
166: .decodeURLToken(this .urlPattern));
167: if (pathInfo != null)
168: pathInfo
169: .append(WinstoneRequest
170: .decodeURLToken(inputPattern
171: .substring(this .urlPattern
172: .length())));
173: return true;
174: } else
175: return false;
176:
177: case EXTENSION_PATTERN:
178: // Strip down to the last item in the path
179: int slashPos = inputPattern.lastIndexOf(SLASH);
180: if ((slashPos == -1)
181: || (slashPos == inputPattern.length() - 1))
182: return false;
183: String fileName = inputPattern.substring(slashPos + 1);
184: if ((this .isPatternFirst && fileName
185: .startsWith(this .urlPattern))
186: || (!this .isPatternFirst && fileName
187: .endsWith(this .urlPattern))) {
188: if (servletPath != null)
189: servletPath.append(WinstoneRequest
190: .decodeURLToken(inputPattern));
191: return true;
192: } else
193: return false;
194:
195: case EXACT_PATTERN:
196: if (inputPattern.equals(this .urlPattern)) {
197: if (servletPath != null)
198: servletPath.append(WinstoneRequest
199: .decodeURLToken(inputPattern));
200: return true;
201: } else
202: return false;
203:
204: case DEFAULT_SERVLET:
205: if (servletPath != null)
206: servletPath.append(WinstoneRequest
207: .decodeURLToken(inputPattern));
208: return true;
209:
210: default:
211: return false;
212: }
213: }
214:
215: /**
216: * Used to compare two url patterns. Always sorts so that lowest pattern
217: * type then longest path come first.
218: */
219: public int compare(Object objOne, Object objTwo) {
220: Mapping one = (Mapping) objOne;
221: Mapping two = (Mapping) objTwo;
222:
223: Integer intOne = new Integer(one.getPatternType());
224: Integer intTwo = new Integer(two.getPatternType());
225: int order = -1 * intOne.compareTo(intTwo);
226: if (order != 0) {
227: return order;
228: }
229: if (one.getLinkName() != null) {
230: // servlet name mapping - just alphabetical sort
231: return one.getLinkName().compareTo(two.getLinkName());
232: } else {
233: return -1
234: * one.getUrlPattern()
235: .compareTo(two.getUrlPattern());
236: }
237: }
238:
239: public String toString() {
240: return this .linkName != null ? "Link:" + this .linkName
241: : "URLPattern:type=" + this .patternType + ",pattern="
242: + this.urlPattern;
243: }
244: }
|