001: /*
002: * $Id: RestfulActionMapper.java 471756 2006-11-06 15:01:43Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.dispatcher.mapper;
022:
023: import java.net.URLDecoder;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.Map;
027: import java.util.StringTokenizer;
028:
029: import javax.servlet.http.HttpServletRequest;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.struts2.RequestUtils;
034:
035: import com.opensymphony.xwork2.config.ConfigurationManager;
036:
037: /**
038: * <!-- START SNIPPET: description -->
039: *
040: * A custom action mapper using the following format:
041: * <p/>
042: * <p/>
043: * <ul><tt>http://HOST/ACTION_NAME/PARAM_NAME1/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
044: * <p/>
045: * You can have as many parameters you'd like to use. Alternatively the URL can be shortened to the following:
046: * <p/>
047: * <ul><tt>http://HOST/ACTION_NAME/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
048: * <p/>
049: * This is the same as:
050: * <p/>
051: * <ul><tt>http://HOST/ACTION_NAME/ACTION_NAME + "Id"/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
052: * <p/>
053: * Suppose for example we would like to display some articles by id at using the following URL sheme:
054: * <p/>
055: * <ul><tt>http://HOST/article/Id</tt></ul>
056: * <p/>
057: * <p/>
058: * Your action just needs a setArticleId() method, and requests such as /article/1, /article/2, etc will all map
059: * to that URL pattern.
060: *
061: * <!-- END SNIPPET: description -->
062: *
063: */
064: public class RestfulActionMapper implements ActionMapper {
065: protected static final Log LOG = LogFactory
066: .getLog(RestfulActionMapper.class);
067:
068: /* (non-Javadoc)
069: * @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
070: */
071: public ActionMapping getMapping(HttpServletRequest request,
072: ConfigurationManager configManager) {
073: String uri = RequestUtils.getServletPath(request);
074:
075: int nextSlash = uri.indexOf('/', 1);
076: if (nextSlash == -1) {
077: return null;
078: }
079:
080: String actionName = uri.substring(1, nextSlash);
081: HashMap<String, String> parameters = new HashMap<String, String>();
082: try {
083: StringTokenizer st = new StringTokenizer(uri
084: .substring(nextSlash), "/");
085: boolean isNameTok = true;
086: String paramName = null;
087: String paramValue;
088:
089: // check if we have the first parameter name
090: if ((st.countTokens() % 2) != 0) {
091: isNameTok = false;
092: paramName = actionName + "Id";
093: }
094:
095: while (st.hasMoreTokens()) {
096: if (isNameTok) {
097: paramName = URLDecoder.decode(st.nextToken(),
098: "UTF-8");
099: isNameTok = false;
100: } else {
101: paramValue = URLDecoder.decode(st.nextToken(),
102: "UTF-8");
103:
104: if ((paramName != null) && (paramName.length() > 0)) {
105: parameters.put(paramName, paramValue);
106: }
107:
108: isNameTok = true;
109: }
110: }
111: } catch (Exception e) {
112: LOG.warn(e);
113: }
114:
115: return new ActionMapping(actionName, "", "", parameters);
116: }
117:
118: /* (non-Javadoc)
119: * @see org.apache.struts2.dispatcher.mapper.ActionMapper#getUriFromActionMapping(org.apache.struts2.dispatcher.mapper.ActionMapping)
120: */
121: public String getUriFromActionMapping(ActionMapping mapping) {
122: String base = mapping.getNamespace() + mapping.getName();
123: for (Iterator iterator = mapping.getParams().entrySet()
124: .iterator(); iterator.hasNext();) {
125: Map.Entry entry = (Map.Entry) iterator.next();
126: String name = (String) entry.getKey();
127: if (name.equals(mapping.getName() + "Id")) {
128: base = base + "/" + entry.getValue();
129: break;
130: }
131: }
132:
133: return base;
134: }
135: }
|