001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.acting;
018:
019: import java.util.Collections;
020: import java.util.Enumeration;
021: import java.util.HashMap;
022: import java.util.Map;
023: import java.util.StringTokenizer;
024: import java.util.Iterator;
025: import org.apache.avalon.framework.parameters.Parameters;
026: import org.apache.cocoon.environment.ObjectModelHelper;
027: import org.apache.cocoon.environment.Redirector;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.environment.SourceResolver;
030:
031: /**
032: * This action simply checks to see if a given request parameter
033: * exists. It takes an arbitrary number of default parameters to check
034: * named 'parameter-name'. Non-default parameters need to be separated
035: * by spaces and passed as value of a sitemap parameter named
036: * 'parameters'. The action returns a map with all parameters if all
037: * of them exist and null otherwise. Parameter names can only be added
038: * to this list but no default parameters can be overridden by
039: * specific ones.
040: *
041: * <p>This action is very closely related to @link{RequestParamAction}
042: * and {@link FormValidatorAction}. However this action is considerably
043: * simpler in that it tests only for existence of a parameter and it
044: * doesn't need a descriptor. Besides it doesn't propagate all request
045: * parameters to the sitemap but only those that are marked as
046: * required.</p> <p> One special feature is, however, that parameters
047: * can contain <strong>one</strong> wildcard ("*"). It will be
048: * checked, whether all parameters with a wildcard have the same
049: * matches. E.g. "id_* name_*" enforces, that if "id_1" exists,
050: * "name_1" must also exist and vice versa.</p>
051: *
052: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
053: * @version CVS $Id: RequestParameterExistsAction.java 433543 2006-08-22 06:22:54Z crossley $
054: */
055: public class RequestParameterExistsAction extends
056: AbstractConfigurableAction {
057:
058: protected static class StringParts {
059: String prefix = null;
060: String pstfix = null;
061: int count = 0;
062:
063: public StringParts(String pre, String post) {
064: prefix = pre;
065: pstfix = post;
066: }
067: }
068:
069: public Map act(Redirector redirector, SourceResolver resolver,
070: Map objectModel, String source, Parameters parameters)
071: throws Exception {
072: Request request = ObjectModelHelper.getRequest(objectModel);
073: HashMap results = new HashMap();
074: HashMap items = new HashMap();
075: int wildcards = 0;
076:
077: // check default parameters for existence
078: if (this .getLogger().isDebugEnabled()) {
079: getLogger().debug("checking default parameters");
080: }
081: Iterator reqParams = settings.values().iterator();
082: while (reqParams.hasNext()) {
083: String paramName = (String) reqParams.next();
084: StringParts sp = splitParameter(paramName);
085: if (sp != null) {
086: // wildcard: special care required (deferred until later)
087: items.put(new Integer(wildcards++), sp);
088: if (this .getLogger().isDebugEnabled()) {
089: getLogger().debug(
090: "(default) deferring " + paramName);
091: }
092: } else {
093: String paramValue = request.getParameter(paramName);
094: if (paramValue == null) {
095: return null;
096: }
097: results.put(paramName, paramValue);
098: }
099: }
100:
101: // check parameters for existence
102: if (this .getLogger().isDebugEnabled()) {
103: getLogger().debug("checking sitemap parameters");
104: }
105: String params = parameters.getParameter("parameters", null);
106: if (params != null) {
107: StringTokenizer st = new StringTokenizer(params);
108: while (st.hasMoreTokens()) {
109: String paramName = st.nextToken();
110: StringParts sp = splitParameter(paramName);
111: if (sp != null) {
112: // wildcard: special care required (deferred until later)
113: items.put(new Integer(wildcards++), sp);
114: if (this .getLogger().isDebugEnabled()) {
115: getLogger().debug("deferring " + paramName);
116: }
117: } else {
118:
119: String paramValue = request.getParameter(paramName);
120: if (paramValue == null) {
121: return null;
122: }
123: results.put(paramName, paramValue);
124: }
125: }
126: }
127:
128: if (wildcards != 0) {
129: // special care for parameters with wildcard
130: //
131: if (this .getLogger().isDebugEnabled()) {
132: getLogger().debug(
133: "deferred checking for parameters: "
134: + wildcards);
135: }
136:
137: // first one
138: //
139: if (this .getLogger().isDebugEnabled()) {
140: getLogger().debug(" checking first");
141: }
142: HashMap values = new HashMap();
143: StringParts sp1 = (StringParts) items.get(new Integer(0));
144: if (this .getLogger().isDebugEnabled()) {
145: getLogger().debug(
146: " Parameter is [" + sp1.prefix + " * "
147: + sp1.pstfix + "] ");
148: }
149: Enumeration requestParams = request.getParameterNames();
150: Boolean dummy = Boolean.TRUE;
151: while (requestParams.hasMoreElements()) {
152: String paramName = (String) requestParams.nextElement();
153: String match = getMatch(paramName, sp1);
154: if (match != null) {
155: if (this .getLogger().isDebugEnabled()) {
156: getLogger().debug(
157: " value is >" + match + "< "
158: + sp1.prefix.length() + " "
159: + paramName.length() + " "
160: + sp1.pstfix.length());
161: }
162: values.put(match, dummy);
163: sp1.count++;
164: if (this .getLogger().isDebugEnabled()) {
165: getLogger().debug(
166: " Parameter " + sp1.prefix + "*"
167: + sp1.pstfix + " matches "
168: + paramName + " (" + sp1.count
169: + " so far)");
170: }
171: String paramValue = request.getParameter(paramName);
172: if (paramValue == null) {
173: return null;
174: }
175: results.put(paramName, paramValue);
176: }
177: }
178:
179: if (sp1.count == 0) {
180: if (this .getLogger().isDebugEnabled()) {
181: getLogger().debug(
182: " Parameter " + sp1.prefix + "*"
183: + sp1.pstfix + " matches "
184: + sp1.count);
185: }
186: return null;
187: }
188:
189: // all other ones
190: //
191: if (this .getLogger().isDebugEnabled()) {
192: getLogger().debug(" checking others");
193: }
194: requestParams = request.getParameterNames();
195: while (requestParams.hasMoreElements()) {
196: String paramName = (String) requestParams.nextElement();
197: if (this .getLogger().isDebugEnabled()) {
198: getLogger()
199: .debug(
200: " checking request parameter "
201: + paramName);
202: }
203: for (int i = wildcards - 1; i > 0; i--) {
204: if (this .getLogger().isDebugEnabled()) {
205: getLogger().debug(" checking against " + i);
206: }
207: StringParts sp = (StringParts) items
208: .get(new Integer(i));
209: String match = getMatch(paramName, sp);
210: if (this .getLogger().isDebugEnabled()) {
211: getLogger().debug(
212: " Parameter is [" + sp.prefix + " * "
213: + sp.pstfix + "] ");
214: }
215: if (match != null) {
216: if (this .getLogger().isDebugEnabled()) {
217: getLogger().debug(
218: " Parameter " + sp.prefix + "*"
219: + sp.pstfix + " matches "
220: + paramName + " ("
221: + sp.count + " so far)");
222: }
223: if (values.containsKey(match)) {
224: sp.count++;
225: if (this .getLogger().isDebugEnabled()) {
226: getLogger().debug(
227: " " + paramName
228: + " (verified)");
229: }
230: String paramValue = request
231: .getParameter(paramName);
232: if (paramValue == null) {
233: return null;
234: }
235: results.put(paramName, paramValue);
236:
237: } else {
238: if (this .getLogger().isDebugEnabled()) {
239: getLogger().debug(
240: "Match " + match
241: + "not found for "
242: + sp1.prefix + "*"
243: + sp1.pstfix
244: + " but for "
245: + sp.prefix + "*"
246: + sp.pstfix);
247: }
248: return null;
249: }
250: }
251: }
252: }
253:
254: // since we enforce that only matches are counted, that exist for
255: // the first parameter as well, check if every parameter has an
256: // equal number of matches.
257: //
258: if (this .getLogger().isDebugEnabled()) {
259: getLogger().debug("checking number of matches");
260: }
261: for (int i = wildcards - 1; i > 0; i--) {
262: StringParts sp = (StringParts) items
263: .get(new Integer(i));
264: if (sp.count != sp1.count) {
265: if (this .getLogger().isDebugEnabled()) {
266: getLogger().debug(
267: "Found " + sp.count + " matches for "
268: + sp.prefix + "*" + sp.pstfix
269: + " but expected " + sp1.count);
270: }
271: return null;
272: } else {
273: if (this .getLogger().isDebugEnabled()) {
274: getLogger().debug(
275: "Found " + sp.count + " matches for "
276: + sp.prefix + "*" + sp.pstfix
277: + " as expected");
278: }
279: }
280: }
281:
282: }
283:
284: return Collections.unmodifiableMap(results);
285: }
286:
287: /**
288: * Find first "*" in a String and split it into the substring
289: * before and after the "*". Returns null if no "*" is present.
290: */
291: protected StringParts splitParameter(String paramName) {
292: int idx = paramName.indexOf("*");
293: if (idx != -1) {
294: return new StringParts(paramName.substring(0, idx),
295: paramName.substring(idx + 1));
296: } else {
297: return null;
298: }
299: }
300:
301: /**
302: * If a String matches a StringPart spec, return the substring
303: * between the specified prefix and postfix. Returns null if it
304: * doesn't match.
305: */
306: protected String getMatch(String paramName, StringParts sp) {
307: if (paramName.startsWith(sp.prefix)
308: && paramName.endsWith(sp.pstfix)) {
309: return paramName.substring(sp.prefix.length(), (paramName
310: .length() - sp.pstfix.length()));
311: } else {
312: return null;
313: }
314: }
315:
316: }
|