001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.rules.metadata;
051:
052: import java.util.StringTokenizer;
053: import java.net.URL;
054: import org.jaffa.cache.CacheManager;
055: import org.jaffa.cache.ICache;
056: import org.jaffa.util.URLHelper;
057: import org.jaffa.datatypes.Parser;
058: import org.jaffa.util.DefaultEntityResolver;
059: import org.jaffa.util.DefaultErrorHandler;
060:
061: import org.xml.sax.helpers.XMLReaderFactory;
062: import org.xml.sax.XMLReader;
063: import org.xml.sax.InputSource;
064: import org.xml.sax.helpers.DefaultHandler;
065: import org.xml.sax.Attributes;
066:
067: import org.xml.sax.SAXException;
068: import java.io.IOException;
069: import java.io.FileNotFoundException;
070: import java.net.MalformedURLException;
071: import org.jaffa.config.Config;
072:
073: /** This parses the Validator config file and creates instances of the FieldValidatorMetaData class. The instances will be cached.
074: */
075: public class ValidatorMetaDataService {
076:
077: private static final String PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
078: private static final String XML_FILE = "classpath:///resources/validators.xml";
079: private static final String SUCCESS_MESSAGE = ValidatorMetaDataService.class
080: .getName();
081: private static ICache c_cache = CacheManager
082: .getCache(ValidatorMetaDataService.class.getName());
083:
084: /** This will return a FieldValidatorMetaData instance for the input name. A null will be returned, in case no definition is found in the Validator config file.
085: * @param name The name of the validator.
086: * @return a FieldValidatorMetaData instance
087: * @throws SAXException If any exception is thrown while parsing the XML file.
088: * @throws IOException If any I/O error occurs in reading the XML file. Note: A FileNotFoundException will be thrown, in case the file is not found.
089: */
090: public static FieldValidatorMetaData getFieldValidatorMetaData(
091: String name) throws SAXException, IOException {
092: if (!c_cache.containsKey(name))
093: find(name);
094: return (FieldValidatorMetaData) c_cache.get(name);
095: }
096:
097: /** Parse the validator-xml file for the given named validator.
098: */
099: private synchronized static void find(String name)
100: throws SAXException, IOException {
101: if (c_cache.containsKey(name))
102: return;
103:
104: CustomHandler handler = null;
105: URL url = null;
106: String validatorFiles = (String) Config.getProperty(
107: Config.PROP_RULES_ENGINE_VALIDATORS_URL_LIST, XML_FILE);
108: for (StringTokenizer strtknzr = new StringTokenizer(
109: validatorFiles, ","); strtknzr.hasMoreTokens();) {
110: String validatorFile = strtknzr.nextToken();
111:
112: try {
113: url = URLHelper.newExtendedURL(validatorFile);
114: } catch (MalformedURLException e) {
115: url = null;
116: }
117: if (url == null)
118: throw new FileNotFoundException("File not found - "
119: + validatorFile);
120:
121: try {
122: handler = new CustomHandler(name);
123: XMLReader reader = XMLReaderFactory
124: .createXMLReader(PARSER_NAME);
125: reader.setContentHandler(handler);
126: reader.setEntityResolver(new DefaultEntityResolver());
127: reader.setErrorHandler(new DefaultErrorHandler());
128: reader.parse(new InputSource(url.openStream()));
129: } catch (SAXException e) {
130: // Its alrite if the SUCCESS_MESSAGE is returned
131: if (SUCCESS_MESSAGE.equals(e.getMessage())
132: && handler != null)
133: break;
134: else
135: throw e;
136: } catch (IOException e) {
137: throw e;
138: }
139: if (handler.getFieldValidatorMetaData() != null)
140: break;
141: }
142: c_cache.put(name, handler != null ? handler
143: .getFieldValidatorMetaData() : null);
144: }
145:
146: /** This will handle the SAX events raised while parsing the validators.xml file. */
147: private static class CustomHandler extends DefaultHandler {
148: private static final String FIELD_VALIDATOR = "field-validator";
149: private static final String NAME = "name";
150: private static final String DESCRIPTION = "description";
151: private static final String CLASS = "class";
152: private static final String MANDATORY = "mandatory";
153: private static final String PARAM = "param";
154: private static final String VALUE = "value";
155:
156: private String m_name = null;
157: private FieldValidatorMetaData m_fieldValidatorMetaData = null;
158: private String m_contents = null;
159:
160: /** Create an instance.
161: */
162: private CustomHandler(String name) {
163: m_name = name;
164: }
165:
166: /** Receive notification of the start of an element.
167: * @param uri The uri.
168: * @param sName The local name (without prefix), or the empty string if Namespace processing is not being performed.
169: * @param qName The qualified name (with prefix), or the empty string if qualified names are not available.
170: * @param atts The specified or defaulted attributes
171: */
172: public void startElement(String uri, String sName,
173: String qName, Attributes atts) {
174: if (m_fieldValidatorMetaData != null) {
175: if (sName.equals(PARAM)) {
176: m_fieldValidatorMetaData.addParameter(atts
177: .getValue(NAME), atts.getValue(VALUE));
178: }
179: }
180: }
181:
182: /** Receive notification of the end of an element.
183: * @param uri The uri.
184: * @param sName The local name (without prefix), or the empty string if Namespace processing is not being performed.
185: * @param qName The qualified name (with prefix), or the empty string if qualified names are not available.
186: * @throws SAXException Any SAX exception, possibly wrapping another exception. NOTE: This exception will also be thrown after the named validator is found, so as to terminate any further parsing.
187: */
188: public void endElement(String uri, String sName, String qName)
189: throws SAXException {
190: if (sName.equals(NAME) && m_name.equals(m_contents)) {
191: m_fieldValidatorMetaData = new FieldValidatorMetaData();
192: m_fieldValidatorMetaData.setName(m_contents);
193: } else if (m_fieldValidatorMetaData != null) {
194: if (sName.equals(DESCRIPTION)) {
195: m_fieldValidatorMetaData.setDescription(m_contents);
196: } else if (sName.equals(CLASS)) {
197: m_fieldValidatorMetaData.setClassName(m_contents);
198: } else if (sName.equals(MANDATORY)) {
199: m_fieldValidatorMetaData.setMandatory(Parser
200: .parseBoolean(m_contents).booleanValue());
201: } else if (sName.equals(FIELD_VALIDATOR)) {
202: // the validator has been found. End the parsing
203: throw new SAXException(SUCCESS_MESSAGE);
204: }
205: }
206: }
207:
208: /** Receive notification of character data inside an element.
209: * @param ch The characters.
210: * @param start The start position in the character array.
211: * @param length The number of characters to use from the character array.
212: */
213: public void characters(char[] ch, int start, int length) {
214: m_contents = new String(ch, start, length);
215: }
216:
217: /** Returns the FieldValidatorMetaData for the given name. A null may be returned, if no matching definition was found.
218: */
219: private FieldValidatorMetaData getFieldValidatorMetaData() {
220: return m_fieldValidatorMetaData;
221: }
222: }
223:
224: public static void main(String[] args) {
225: try {
226: System.out
227: .println(getFieldValidatorMetaData("generic-foreign-key"));
228: } catch (Exception e) {
229: e.printStackTrace();
230: }
231: }
232: }
|