001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.faces;
034:
035: import com.flexive.shared.exceptions.FxInvalidParameterException;
036: import com.flexive.shared.exceptions.FxNotFoundException;
037: import org.apache.commons.lang.StringUtils;
038: import org.apache.commons.logging.Log;
039: import org.apache.commons.logging.LogFactory;
040:
041: import java.util.HashMap;
042: import java.util.Map;
043: import java.util.regex.Matcher;
044: import java.util.regex.Pattern;
045:
046: /**
047: * <p>A base implementation of an URI route. This class allows to define static mappers
048: * for URI. External URIs can be parsed using {@link #getMatcher(String)} and created
049: * with {@link #getMappedUri(java.util.Map)}. This implementation provides simple string-based,
050: * named parameters that can be specified in the URI using "${parameter}", e.g.
051: * "/myUri/${myParam}.xhtml". Subclasses like the {@link ContentURIRoute} provide more
052: * specialized parameters.</p>
053: * <p>
054: * Although this class provides a complete implementation, it is declared abstract since
055: * any usable URI mapper must define at least one static parameter.
056: * </p>
057: *
058: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
059: * @version $Rev: 1 $
060: */
061: public abstract class URIRoute {
062: private static final transient Log LOG = LogFactory
063: .getLog(URIRoute.class);
064:
065: protected static final Map<String, String> PARAMETERS = new HashMap<String, String>();
066: protected final Pattern pattern;
067: protected final String format;
068: protected final String target;
069: private final Map<String, Integer> positions = new HashMap<String, Integer>();
070:
071: protected URIRoute(String target, String format) {
072: this .target = target;
073: this .format = format;
074: this .pattern = Pattern.compile(buildRegexp(format));
075: }
076:
077: /**
078: * Returns the target URI of this mapper.
079: *
080: * @return the target URI of this mapper.
081: */
082: public String getTarget() {
083: return target;
084: }
085:
086: /**
087: * Return the URI format of this mapper.
088: *
089: * @return the URI format of this mapper.
090: */
091: public String getFormat() {
092: return format;
093: }
094:
095: /**
096: * Return a matcher for the given URI. The matcher allows to extract parameters
097: * set in the URI.
098: *
099: * @param uri the URI (matching this mapper's URI format) to be parsed
100: * @return a matcher for the given URI
101: */
102: public URIMatcher getMatcher(String uri) {
103: final Matcher matcher = pattern.matcher(uri);
104: matcher.find();
105: return new URIMatcher(this , uri, matcher);
106: }
107:
108: /**
109: * Replaces the given parameters in this mapper's URI format and returns the created URI.
110: * Note that the given parameters must include <b>all</b> parameters set in the format,
111: * although not all parameters specified have to be included in the format.
112: *
113: * @param parameters the parameter values to be replaced
114: * @return a formatted URI
115: */
116: public String getMappedUri(Map<String, String> parameters) {
117: String uri = format;
118: int replacements = 0;
119: for (Map.Entry<String, String> entry : parameters.entrySet()) {
120: if (hasParameter(entry.getKey())) {
121: uri = replaceUriParameter(uri, entry.getKey(), entry
122: .getValue());
123: replacements++;
124: }
125: }
126: if (replacements != positions.size()) {
127: throw new FxInvalidParameterException("parameters", LOG,
128: "ex.uriRoute.parameter.missing", format, uri)
129: .asRuntimeException();
130: }
131: return uri;
132: }
133:
134: private String buildRegexp(String format) {
135: final StringBuilder out = new StringBuilder();
136: int pos = 0;
137: int nextParameter = format.indexOf("${", pos);
138: int parameterPos = 0;
139: while (nextParameter != -1) {
140: out.append(format, pos, nextParameter);
141: final int endIndex = format.indexOf('}', nextParameter + 2);
142: if (endIndex == -1) {
143: throw new FxInvalidParameterException("format", LOG,
144: "ex.uriRoute.format.closing", format)
145: .asRuntimeException();
146: }
147: final String name = format.substring(nextParameter + 2,
148: endIndex);
149: if (StringUtils.isBlank(name)) {
150: throw new FxInvalidParameterException("format", LOG,
151: "ex.uriRoute.format.emptyParameter", format)
152: .asRuntimeException();
153: }
154: if (positions.containsKey(name)) {
155: throw new FxInvalidParameterException("format", LOG,
156: "ex.uriRoute.format.uniqueParameter", name,
157: format).asRuntimeException();
158: }
159: positions.put(name, ++parameterPos);
160: out.append(getParameterRegexp(name));
161: pos = endIndex + 1;
162: nextParameter = format.indexOf("${", pos);
163: }
164: // append characters after last match and return formatted string
165: return out.append(format, pos, format.length()).toString();
166: }
167:
168: /**
169: * Replace the given parameter in the URI format string.
170: *
171: * @param format the format string
172: * @param parameterName the parameter name
173: * @param value the value to be set for the parameter
174: * @return the replaced format string
175: */
176: protected String replaceUriParameter(String format,
177: String parameterName, String value) {
178: // TODO create a more efficient version with string buffers
179: return StringUtils.replace(format, "${" + parameterName + "}",
180: value);
181: }
182:
183: /**
184: * Return the position of the given parameter name in the format string. If the parameter
185: * is not set in the format string, a FxRuntimeException is thrown.
186: *
187: * @param parameterName the parameter name
188: * @return the 1-based position of the parameter in the format string
189: */
190: int getPosition(String parameterName) {
191: if (!positions.containsKey(parameterName)) {
192: throw new FxNotFoundException("parameterName", LOG,
193: "ex.uriRoute.parameter.unknown", parameterName)
194: .asRuntimeException();
195: }
196: return positions.get(parameterName);
197: }
198:
199: /**
200: * Returns true if the given parameter is set in this mapper's format string.
201: *
202: * @param parameterName the parameter name to be checked
203: * @return true if the given parameter is set in this mapper's format string.
204: */
205: boolean hasParameter(String parameterName) {
206: return positions.containsKey(parameterName);
207: }
208:
209: /**
210: * Returns the regular expression of the given parameter, or throws a
211: * FxRuntimeException if the parameter is not available in this mapper.
212: *
213: * @param name the parameter name
214: * @return the regular expression of the given parameter
215: */
216: protected String getParameterRegexp(String name) {
217: if (!PARAMETERS.containsKey(name)) {
218: throw new FxInvalidParameterException("name", LOG,
219: "ex.uriRoute.parameter.unknown", name)
220: .asRuntimeException();
221: }
222: return PARAMETERS.get(name);
223: }
224: }
|