001: /*
002: * argun 1.0
003: * Web 2.0 delivery framework
004: * Copyright (C) 2007 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.web.menu.matchers;
024:
025: import java.lang.reflect.Constructor;
026: import java.lang.reflect.InvocationTargetException;
027: import java.util.HashMap;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031:
032: import javax.servlet.http.HttpServletRequest;
033: import javax.xml.transform.TransformerException;
034:
035: import org.apache.log4j.Logger;
036: import org.apache.xpath.CachedXPathAPI;
037: import org.w3c.dom.Element;
038:
039: import biz.hammurapi.web.HammurapiWebException;
040:
041: /**
042: * @author Pavel Vlasov
043: * @version $Revision: 1.2 $
044: */
045: public abstract class UriMatcher implements RequestMatcher {
046: static Logger logger = Logger.getLogger(UriMatcher.class);
047: private boolean matchQueryString;
048: private int weight;
049: protected String baseUri;
050:
051: protected UriMatcher(String pattern, String baseUri,
052: boolean matchQueryString, int weight)
053: throws HammurapiWebException {
054: super ();
055: this .matchQueryString = matchQueryString;
056: this .weight = weight;
057:
058: setBaseUri(baseUri);
059: setPattern(pattern);
060: }
061:
062: /**
063: * @param pattern2
064: */
065: protected void setPattern(String pattern) {
066: absolutePattern = (baseUri == null || pattern.startsWith("/")) ? pattern
067: : baseUri + pattern;
068: logger.debug("Absolute pattern: " + absolutePattern);
069: }
070:
071: private void setBaseUri(String baseUri) {
072: if (baseUri == null) {
073: this .baseUri = null;
074: } else {
075: int idx = baseUri.lastIndexOf('/');
076: this .baseUri = idx == -1 ? baseUri : baseUri.substring(0,
077: idx + 1);
078: logger.debug("Base uri: " + this .baseUri);
079: }
080: }
081:
082: protected UriMatcher(Element holder, String baseUri,
083: CachedXPathAPI cxpa) throws HammurapiWebException {
084: super ();
085: matchQueryString = "yes".equals(holder
086: .getAttribute("match-query-string"));
087: if (cxpa == null) {
088: cxpa = new CachedXPathAPI();
089: }
090: if (holder.hasAttribute("weight")) {
091: try {
092: weight = Integer
093: .parseInt(holder.getAttribute("weight"));
094: } catch (NumberFormatException e) {
095: logger.warn("Invalid weight value", e);
096: weight = 0;
097: }
098: }
099:
100: setBaseUri(baseUri);
101: try {
102: setPattern(cxpa.eval(holder, "text()").toString());
103: } catch (TransformerException e) {
104: throw new HammurapiWebException("Can't load pattern text",
105: e);
106: }
107: }
108:
109: public static String requestString(HttpServletRequest request) {
110: String uri = request.getRequestURI();
111: String contextPath = request.getContextPath();
112: if (uri.startsWith(contextPath)) {
113: uri = uri.substring(contextPath.length());
114: }
115: String queryString = request.getQueryString();
116: if (queryString != null) {
117: uri = uri + (uri.indexOf("?") == -1 ? "?" : "&")
118: + queryString;
119: }
120: return uri;
121: }
122:
123: public int getWeight() {
124: return weight;
125: }
126:
127: /**
128: * @param string
129: * @param uri
130: * @param b
131: * @param i
132: * @return
133: */
134: public static UriMatcher newMatcher(String patternLanguage,
135: String pattern, String baseUri, boolean matchQueryString,
136: int weight) throws HammurapiWebException {
137: Class matcherClass = getMatcherClass(patternLanguage);
138: try {
139: Constructor matcherConstructor = matcherClass
140: .getDeclaredConstructor(new Class[] { String.class,
141: String.class, Boolean.TYPE, Integer.TYPE });
142: return (UriMatcher) matcherConstructor
143: .newInstance(new Object[] { pattern, baseUri,
144: Boolean.valueOf(matchQueryString),
145: new Integer(weight) });
146: } catch (NoSuchMethodException e) {
147: throw new HammurapiWebException(
148: "Can't find constructor (String,boolean,int) for "
149: + matcherClass.getName(), e);
150: } catch (IllegalArgumentException e) {
151: throw new HammurapiWebException("Illegal arguments", e);
152: } catch (InstantiationException e) {
153: throw new HammurapiWebException("Can't instantiate "
154: + matcherClass.getName(), e);
155: } catch (IllegalAccessException e) {
156: throw new HammurapiWebException(
157: "Illegal access while instantiating "
158: + matcherClass.getName(), e);
159: } catch (InvocationTargetException e) {
160: throw new HammurapiWebException(
161: "InvocationTargetException while instantiating "
162: + matcherClass.getName(), e);
163: }
164: }
165:
166: protected String getStringToMatch(HttpServletRequest request) {
167: String uri = requestString(request);
168: String bareUri = request.getRequestURI();
169: String contextPath = request.getContextPath();
170: if (bareUri.startsWith(contextPath)) {
171: bareUri = bareUri.substring(contextPath.length());
172: }
173:
174: return matchQueryString ? uri : bareUri;
175: }
176:
177: private static Map languageMap = new HashMap();
178: protected String absolutePattern;
179:
180: static {
181: languageMap.put("exact", ExactUriMatcher.class);
182: languageMap.put("awk", AwkUriMatcher.class);
183: languageMap.put("perl5", Perl5UriMatcher.class);
184: languageMap.put("glob", GlobUriMatcher.class);
185: // TODO Load additional languages from properties and resources.
186: }
187:
188: /**
189: * @param patternLanguage
190: * @return
191: */
192: private static Class getMatcherClass(String patternLanguage) {
193: if (patternLanguage == null) {
194: return ExactUriMatcher.class;
195: }
196:
197: Class ret = (Class) languageMap.get(patternLanguage);
198: if (ret == null) {
199: logger.warn("Pattern language '" + patternLanguage
200: + "' not found, using 'exact'");
201: ret = ExactUriMatcher.class;
202: }
203: return ret;
204: }
205:
206: // public static UriMatcher newMatcher(Element holder, String baseUri, CachedXPathAPI cxpa) throws HammurapiWebException {
207: // Class matcherClass=getMatcherClass(holder.getAttribute("pattern-language"));
208: // try {
209: // Constructor matcherConstructor =
210: // matcherClass.getDeclaredConstructor(
211: // new Class[] { Element.class, String.class, CachedXPathAPI.class });
212: // return (UriMatcher) matcherConstructor.newInstance(
213: // new Object[] { holder, baseUri, cxpa });
214: // } catch (NoSuchMethodException e) {
215: // throw new HammurapiWebException("Can't find constructor (Element, String, CachedXPathAPI) for "+matcherClass.getName(), e);
216: // } catch (IllegalArgumentException e) {
217: // throw new HammurapiWebException("Illegal arguments", e);
218: // } catch (InstantiationException e) {
219: // throw new HammurapiWebException("Can't instantiate "+matcherClass.getName(), e);
220: // } catch (IllegalAccessException e) {
221: // throw new HammurapiWebException("Illegal access while instantiating "+matcherClass.getName(), e);
222: // } catch (InvocationTargetException e) {
223: // throw new HammurapiWebException("InvocationTargetException while instantiating "+matcherClass.getName(), e);
224: // }
225: // }
226:
227: public List matchResult(boolean matched) {
228: List ret = new LinkedList();
229: if (matched) {
230: ret
231: .add(new MatchResult(this , matchQueryString,
232: getWeight()));
233: }
234: return ret;
235: }
236:
237: /* (non-Javadoc)
238: * @see biz.hammurapi.xmenu.RequestMatcher#isMatchQueryString()
239: */
240: public boolean isMatchQueryString() {
241: return matchQueryString;
242: }
243:
244: /**
245: * Calculates absolute pattern based on the pattern and baseUri
246: * @param pattern
247: * @return
248: */
249: public String getAbsolutePattern() {
250: return absolutePattern;
251: }
252:
253: public static String normalizeUrl(String url) {
254: String[] path = url.split("/");
255: int shift = 0;
256: if (url.toLowerCase().startsWith("http://")
257: | url.toLowerCase().startsWith("https://")) {
258: shift = 3;
259: } else if (url.startsWith("/")) {
260: shift = 1;
261: }
262:
263: int j = 0;
264:
265: for (int i = 0; i < path.length - shift; i++, j++) {
266:
267: if (".".equals(path[i + shift])) {
268: j--;
269: } else if ("..".equals(path[i + shift]) && j > 0) {
270: j -= 2;
271: } else {
272: path[j + shift] = path[i + shift];
273: }
274: }
275:
276: StringBuffer sb = new StringBuffer();
277: for (int i = 0; i < j + shift - 1; i++) {
278: sb.append(path[i]);
279: sb.append("/");
280: }
281:
282: sb.append(path[j + shift - 1]);
283:
284: return sb.toString();
285: }
286:
287: }
|