001 package org.apache.fulcrum.intake.transform;
002
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
022 import java.io.BufferedReader;
023 import java.io.FileReader;
024 import java.io.IOException;
025
026 import javax.xml.parsers.ParserConfigurationException;
027 import javax.xml.parsers.SAXParser;
028 import javax.xml.parsers.SAXParserFactory;
029
030 import org.apache.avalon.framework.logger.LogEnabled;
031 import org.apache.avalon.framework.logger.Logger;
032 import org.apache.fulcrum.intake.xmlmodel.AppData;
033 import org.apache.fulcrum.intake.xmlmodel.Rule;
034 import org.apache.fulcrum.intake.xmlmodel.XmlField;
035 import org.apache.fulcrum.intake.xmlmodel.XmlGroup;
036 import org.xml.sax.Attributes;
037 import org.xml.sax.InputSource;
038 import org.xml.sax.SAXException;
039 import org.xml.sax.SAXParseException;
040 import org.xml.sax.helpers.DefaultHandler;
041
042 /**
043 * A Class that is used to parse an input
044 * xml schema file and creates and AppData java structure.
045 * It uses apache Xerces to do the xml parsing.
046 *
047 * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
048 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
049 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
050 * @version $Id: XmlToAppData.java 732101 2009-01-06 20:30:43Z tv $
051 */
052 public class XmlToAppData extends DefaultHandler
053 implements LogEnabled
054 {
055 /** Logging */
056 private Logger log;
057
058 private AppData app;
059 private XmlGroup currGroup;
060 private XmlField currField;
061 private Rule currRule;
062 private String currElement;
063 private StringBuffer chars;
064
065 private static SAXParserFactory saxFactory;
066
067 static
068 {
069 saxFactory = SAXParserFactory.newInstance();
070 saxFactory.setValidating(true);
071 }
072
073 /**
074 * Creates a new instance of the Intake XML Parser
075 */
076 public XmlToAppData()
077 {
078 app = new AppData();
079 }
080
081 /**
082 * Parses a XML input file and returns a newly created and
083 * populated AppData structure.
084 *
085 * @param xmlFile The input file to parse.
086 * @return AppData populated by <code>xmlFile</code>.
087 * @throws ParserConfigurationException
088 * @throws SAXException
089 * @throws IOException
090 */
091 public AppData parseFile(String xmlFile)
092 throws ParserConfigurationException, SAXException, IOException
093 {
094 SAXParser parser = saxFactory.newSAXParser();
095
096 FileReader fr = new FileReader(xmlFile);
097 BufferedReader br = new BufferedReader(fr);
098
099 chars = new StringBuffer();
100
101 try
102 {
103 InputSource is = new InputSource(br);
104 parser.parse(is, this);
105 }
106 finally
107 {
108 br.close();
109 }
110
111 return app;
112 }
113
114 /**
115 * Provide an Avalon logger
116 *
117 * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger)
118 */
119 public void enableLogging(Logger logger)
120 {
121 this.log = logger.getChildLogger("XmlToAppData");
122
123 }
124
125 /**
126 * EntityResolver implementation. Called by the XML parser
127 *
128 * @return an InputSource for the database.dtd file
129 */
130 public InputSource resolveEntity(String publicId, String systemId)
131 {
132 return new DTDResolver().resolveEntity(publicId, systemId);
133 }
134
135 /**
136 * Handles opening elements of the xml file.
137 */
138 public void startElement(String uri, String localName,
139 String rawName, Attributes attributes)
140 {
141 currElement = rawName;
142 if (rawName.equals("input-data"))
143 {
144 app.loadFromXML(attributes);
145 }
146 else if (rawName.equals("group"))
147 {
148 currGroup = app.addGroup(attributes);
149 }
150 else if (rawName.equals("field"))
151 {
152 currField = currGroup.addField(attributes);
153 }
154 else if (rawName.equals("rule"))
155 {
156 currRule = currField.addRule(attributes);
157 }
158 }
159
160 /**
161 * Handles closing elements of the xml file.
162 *
163 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
164 */
165 public void endElement(String uri, String localName, String name) throws SAXException
166 {
167 if ("rule".equals(currElement) && chars.length() > 0)
168 {
169 currRule.setMessage(chars.toString());
170 }
171 else if ("required-message".equals(currElement) && chars.length() > 0)
172 {
173 log.warn("The required-message element is deprecated! " +
174 "You should update your intake.xml file to use the " +
175 "'required' rule instead.");
176 currField.setIfRequiredMessage(chars.toString());
177 }
178
179 chars = new StringBuffer();
180 }
181
182 /**
183 * Handles the character data, which we are using to specify the
184 * error message.
185 */
186 public void characters(char[] mesgArray, int start, int length)
187 {
188 this.chars.append(mesgArray, start, length);
189 }
190
191 /**
192 * Callback function for the xml parser to give warnings.
193 *
194 * @param spe a <code>SAXParseException</code> value
195 */
196 public void warning(SAXParseException spe)
197 {
198 log.warn("Parser Exception: " +
199 "Line " + spe.getLineNumber() +
200 " Row: " + spe.getColumnNumber() +
201 " Msg: " + spe.getMessage());
202 }
203
204 /**
205 * Callback function for the xml parser to give errors.
206 *
207 * @param spe a <code>SAXParseException</code> value
208 */
209 public void error(SAXParseException spe)
210 {
211 log.error("Parser Exception: " +
212 "Line " + spe.getLineNumber() +
213 " Row: " + spe.getColumnNumber() +
214 " Msg: " + spe.getMessage());
215 }
216
217 /**
218 * Callback function for the xml parser to give fatalErrors.
219 *
220 * @param spe a <code>SAXParseException</code> value
221 */
222 public void fatalError(SAXParseException spe)
223 {
224 log.fatalError("Parser Exception: " +
225 "Line " + spe.getLineNumber() +
226 " Row: " + spe.getColumnNumber() +
227 " Msg: " + spe.getMessage());
228 }
229 }