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 }