001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork.validator;
006:
007: import com.opensymphony.xwork.ObjectFactory;
008: import com.opensymphony.xwork.util.DomHelper;
009: import com.opensymphony.xwork.XworkException;
010: import org.w3c.dom.*;
011: import org.xml.sax.InputSource;
012:
013: import java.io.InputStream;
014: import java.util.ArrayList;
015: import java.util.HashMap;
016: import java.util.List;
017: import java.util.Map;
018:
019: /**
020: * Parse the validation file. (eg. MyAction-validation.xml, MyAction-actionAlias-validation.xml)
021: * to return a List of ValidatorConfig encapsulating the validator information.
022: *
023: * @author Jason Carreira
024: * @author James House
025: * @author tm_jee ( tm_jee (at) yahoo.co.uk )
026: * @author Rob Harrop
027: * @author Rene Gielen
028: *
029: * @see com.opensymphony.xwork.validator.ValidatorConfig
030: */
031: public class ValidatorFileParser {
032:
033: static final String MULTI_TEXTVALUE_SEPARATOR = " ";
034:
035: /**
036: * Parse resource for a list of ValidatorConfig objects.
037: *
038: * @param is input stream to the resource
039: * @param resourceName file name of the resource
040: * @return List list of ValidatorConfig
041: */
042: public static List parseActionValidatorConfigs(InputStream is,
043: final String resourceName) {
044: List validatorCfgs = new ArrayList();
045: Document doc = null;
046:
047: InputSource in = new InputSource(is);
048: in.setSystemId(resourceName);
049:
050: Map dtdMappings = new HashMap();
051: dtdMappings.put(
052: "-//OpenSymphony Group//XWork Validator 1.0//EN",
053: "xwork-validator-1.0.dtd");
054: dtdMappings.put(
055: "-//OpenSymphony Group//XWork Validator 1.0.2//EN",
056: "xwork-validator-1.0.2.dtd");
057:
058: doc = DomHelper.parse(in, dtdMappings);
059:
060: if (doc != null) {
061: NodeList fieldNodes = doc.getElementsByTagName("field");
062:
063: // BUG: xw-305: Let validator be parsed first and hence added to
064: // the beginning of list and therefore evaluated first, so short-circuting
065: // it will not cause field-leve validator to be kicked off.
066: {
067: NodeList validatorNodes = doc
068: .getElementsByTagName("validator");
069: addValidatorConfigs(validatorNodes, new HashMap(),
070: validatorCfgs);
071: }
072:
073: for (int i = 0; i < fieldNodes.getLength(); i++) {
074: Element fieldElement = (Element) fieldNodes.item(i);
075: String fieldName = fieldElement.getAttribute("name");
076: Map extraParams = new HashMap();
077: extraParams.put("fieldName", fieldName);
078:
079: NodeList validatorNodes = fieldElement
080: .getElementsByTagName("field-validator");
081: addValidatorConfigs(validatorNodes, extraParams,
082: validatorCfgs);
083: }
084: }
085:
086: return validatorCfgs;
087: }
088:
089: /**
090: * Parses validator definitions
091: *
092: * @deprecated Use parseValidatorDefinitions(InputStream, String)
093: * @param is The input stream
094: */
095: public static void parseValidatorDefinitions(InputStream is) {
096: parseValidatorDefinitions(is, null);
097: }
098:
099: /**
100: * Parses validator definitions
101: *
102: * @since 1.2
103: * @param is The input stream
104: * @param resourceName The location of the input stream
105: */
106: public static void parseValidatorDefinitions(InputStream is,
107: String resourceName) {
108:
109: InputSource in = new InputSource(is);
110: in.setSystemId(resourceName);
111:
112: Document doc = DomHelper.parse(in);
113:
114: NodeList nodes = doc.getElementsByTagName("validator");
115:
116: for (int i = 0; i < nodes.getLength(); i++) {
117: Element validatorElement = (Element) nodes.item(i);
118: String name = validatorElement.getAttribute("name");
119: String className = validatorElement.getAttribute("class");
120:
121: try {
122: // catch any problems here
123: ObjectFactory.getObjectFactory().buildValidator(
124: className, new HashMap(), null);
125: ValidatorFactory.registerValidator(name, className);
126: } catch (Exception e) {
127: throw new XworkException(
128: "Unable to load validator class " + className,
129: e, validatorElement);
130: }
131: }
132: }
133:
134: /**
135: * Extract trimmed text value from the given DOM element, ignoring XML comments. Appends all CharacterData nodes
136: * and EntityReference nodes into a single String value, excluding Comment nodes.
137: * This method is based on a method originally found in DomUtils class of Springframework.
138: *
139: * @see org.w3c.dom.CharacterData
140: * @see org.w3c.dom.EntityReference
141: * @see org.w3c.dom.Comment
142: */
143: public static String getTextValue(Element valueEle) {
144: StringBuffer value = new StringBuffer();
145: NodeList nl = valueEle.getChildNodes();
146: boolean firstCDataFound = false;
147: for (int i = 0; i < nl.getLength(); i++) {
148: Node item = nl.item(i);
149: if ((item instanceof CharacterData && !(item instanceof Comment))
150: || item instanceof EntityReference) {
151: final String nodeValue = item.getNodeValue();
152: if (nodeValue != null) {
153: value.append(nodeValue.trim());
154: }
155: }
156: }
157: return value.toString().trim();
158: }
159:
160: private static void addValidatorConfigs(NodeList validatorNodes,
161: Map extraParams, List validatorCfgs) {
162: for (int j = 0; j < validatorNodes.getLength(); j++) {
163: Element validatorElement = (Element) validatorNodes.item(j);
164: String validatorType = validatorElement
165: .getAttribute("type");
166: Map params = new HashMap(extraParams);
167: NodeList paramNodes = validatorElement
168: .getElementsByTagName("param");
169:
170: for (int k = 0; k < paramNodes.getLength(); k++) {
171: Element paramElement = (Element) paramNodes.item(k);
172: String paramName = paramElement.getAttribute("name");
173: params.put(paramName, getTextValue(paramElement));
174: }
175:
176: // ensure that the type is valid...
177: ValidatorFactory
178: .lookupRegisteredValidatorType(validatorType);
179:
180: ValidatorConfig vCfg = new ValidatorConfig(validatorType,
181: params);
182: vCfg.setLocation(DomHelper
183: .getLocationObject(validatorElement));
184:
185: vCfg.setShortCircuit(Boolean.valueOf(
186: validatorElement.getAttribute("short-circuit"))
187: .booleanValue());
188:
189: NodeList messageNodes = validatorElement
190: .getElementsByTagName("message");
191: Element messageElement = (Element) messageNodes.item(0);
192: String key = messageElement.getAttribute("key");
193:
194: if ((key != null) && (key.trim().length() > 0)) {
195: vCfg.setMessageKey(key);
196: }
197:
198: final Node defaultMessageNode = messageElement
199: .getFirstChild();
200: String defaultMessage = (defaultMessageNode == null) ? ""
201: : defaultMessageNode.getNodeValue();
202: vCfg.setDefaultMessage(defaultMessage);
203: validatorCfgs.add(vCfg);
204: }
205: }
206: }
|