001 /*
002 * ConfigXmlHandler.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Hamish Cunningham, 9/Nov/2000
013 *
014 * $Id: ConfigXmlHandler.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015 */
016
017 package gate.config;
018
019 import java.net.MalformedURLException;
020 import java.net.URL;
021 import java.util.List;
022 import java.util.Stack;
023
024 import org.xml.sax.*;
025 import org.xml.sax.helpers.DefaultHandler;
026
027 import gate.*;
028 import gate.creole.ResourceInstantiationException;
029 import gate.util.*;
030 import gate.xml.SimpleErrorHandler;
031
032
033 /** This is a SAX handler for processing <CODE>gate.xml</CODE> files.
034 */
035 public class ConfigXmlHandler extends DefaultHandler {
036
037 /** A stack to stuff PCDATA onto for reading back at element ends.
038 * (Probably redundant to have a stack as we only push one item
039 * onto it. Probably. Ok, so I should check, but a) it works, b)
040 * I'm bald already and c) life is short.)
041 */
042 private Stack contentStack = new Stack();
043
044 /** The current resource data object */
045 private SystemData systemData;
046
047 /** The current element's attribute list */
048 private Attributes currentAttributes;
049
050 /** A feature map representation of the current element's attribute list */
051 private FeatureMap currentAttributeMap;
052
053 /** Debug flag */
054 private static final boolean DEBUG = false;
055
056 /** The source URL of the config file being parsed. */
057 private URL sourceUrl;
058
059 /** This object indicates what to do when the parser encounts an error*/
060 private SimpleErrorHandler _seh = new SimpleErrorHandler();
061
062
063 /** This is used to capture all data within two tags before calling the actual characters method */
064 private StringBuffer contentBuffer = new StringBuffer("");
065
066 /** This is a variable that shows if characters have been read */
067 private boolean readCharacterStatus = false;
068
069
070 /** Construction */
071 public ConfigXmlHandler(URL configUrl) {
072 this.register = Gate.getCreoleRegister();
073 this.sourceUrl = configUrl;
074 } // construction
075
076 /** The register object that we add CREOLE directories to during parsing.
077 */
078 private CreoleRegister register;
079
080 /** Called when the SAX parser encounts the beginning of the XML document */
081 public void startDocument() throws GateSaxException {
082 if(DEBUG) Out.prln("start document");
083 } // startDocument
084
085 /** Called when the SAX parser encounts the end of the XML document */
086 public void endDocument() throws GateSaxException {
087 if(DEBUG) Out.prln("end document");
088 if(! contentStack.isEmpty()) {
089 StringBuffer errorMessage =
090 new StringBuffer("document ended but element stack not empty:");
091 while(! contentStack.isEmpty())
092 errorMessage.append(Strings.getNl()+" "+(String) contentStack.pop());
093 throw new GateSaxException(errorMessage.toString());
094 }
095 } // endDocument
096
097 /** A verbose method for Attributes*/
098 private String attributes2String(Attributes atts){
099 StringBuffer strBuf = new StringBuffer("");
100 if (atts == null) return strBuf.toString();
101 for (int i = 0; i < atts.getLength(); i++) {
102 String attName = atts.getQName(i);
103 String attValue = atts.getValue(i);
104 strBuf.append(" ");
105 strBuf.append(attName);
106 strBuf.append("=");
107 strBuf.append(attValue);
108 }// End for
109 return strBuf.toString();
110 }// attributes2String()
111
112 /** Called when the SAX parser encounts the beginning of an XML element */
113 public void startElement (
114 String uri, String qName, String elementName, Attributes atts
115 ) throws SAXException {
116
117 // call characterActions
118 if(readCharacterStatus) {
119 readCharacterStatus = false;
120 charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
121 }
122
123 if(DEBUG) {
124 Out.pr("startElement: ");
125 Out.println(
126 elementName + " " +
127 attributes2String(atts)
128 );
129 }
130
131 // record the attributes of this element for endElement()
132 currentAttributes = atts;
133 currentAttributeMap = attributeListToParameterList();
134
135 // if it's a SYSTEM, create a new one and set its name
136 if(elementName.toUpperCase().equals("SYSTEM")) {
137 systemData = new SystemData();
138 for(int i=0, len=currentAttributes.getLength(); i<len; i++) {
139 if(currentAttributes.getQName(i).toUpperCase().equals("NAME"))
140 systemData.systemName = currentAttributes.getValue(i);
141 }
142 } else if(elementName.toUpperCase().equals("DBCONFIG")) {
143 DataStoreRegister.addConfig(currentAttributeMap);
144 } else if(elementName.toUpperCase().equals(Gate.getUserConfigElement())) {
145 Gate.getUserConfig().putAll(currentAttributeMap);
146 }
147
148 } // startElement
149
150 /** Utility function to throw exceptions on stack errors. */
151 private void checkStack(String methodName, String elementName)
152 throws GateSaxException {
153 if(contentStack.isEmpty())
154 throw new GateSaxException(
155 methodName + " called for element " + elementName + " with empty stack"
156 );
157 } // checkStack
158
159 /** Called when the SAX parser encounts the end of an XML element.
160 * This is actions happen.
161 */
162 public void endElement (String uri, String qName, String elementName)
163 throws GateSaxException, SAXException {
164
165 // call characterActions
166 if(readCharacterStatus) {
167 readCharacterStatus = false;
168 charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
169 }
170
171 if(DEBUG) Out.prln("endElement: " + elementName);
172
173 //////////////////////////////////////////////////////////////////
174 if(elementName.toUpperCase().equals("GATE")) {
175
176 //////////////////////////////////////////////////////////////////
177 } else if(elementName.toUpperCase().equals("CREOLE-DIRECTORY")) {
178 String dirUrlName = (String) contentStack.pop();
179 try {
180 register.addDirectory(new URL(dirUrlName));
181 } catch(MalformedURLException e) {
182 throw new GateSaxException("bad URL " + dirUrlName + e);
183 }
184
185 //////////////////////////////////////////////////////////////////
186 } else if(elementName.toUpperCase().equals("SYSTEM")) {
187 // check we got correct params on systemData?
188 systemData.createSystem();
189
190 //////////////////////////////////////////////////////////////////
191 } else if(elementName.toUpperCase().equals("CONTROLLER")) {
192 systemData.controllerTypeName = (String) contentStack.pop();
193
194 //////////////////////////////////////////////////////////////////
195 } else if(elementName.toUpperCase().equals("LR")) {
196 // create an LR and add it to the SystemData
197 createResource((String) contentStack.pop(), systemData.lrList);
198
199 //////////////////////////////////////////////////////////////////
200 } else if(elementName.toUpperCase().equals("PR")) {
201 // create a PR and add it to the SystemData
202 createResource((String) contentStack.pop(), systemData.prList);
203
204 //////////////////////////////////////////////////////////////////
205 } else if(elementName.toUpperCase().equals("DBCONFIG")) {
206 // these are empty elements with attributes; nothing to do here
207
208 //////////////////////////////////////////////////////////////////
209 }else if(elementName.toUpperCase().equals("GATECONFIG")) {
210 // these are empty elements with attributes; nothing to do here
211
212 //////////////////////////////////////////////////////////////////
213 } else {
214 throw new GateSaxException(
215 "Unknown config data element: " + elementName +
216 "; encountered while parsing " + sourceUrl
217 );
218 }
219 //////////////////////////////////////////////////////////////////
220
221 } // endElement
222
223 /** Called when the SAX parser encounts text (PCDATA) in the XML doc */
224 public void characters(char [] text,int start,int length) throws SAXException {
225 if(!readCharacterStatus) {
226 contentBuffer = new StringBuffer(new String(text,start,length));
227 } else {
228 contentBuffer.append(new String(text,start,length));
229 }
230 readCharacterStatus = true;
231 }
232
233 /**
234 * This method is called when all characters between specific tags have been read completely
235 */
236
237 public void charactersAction(char[] text, int start, int length)
238 throws SAXException {
239 // Get the trimmed text between elements
240 String content = new String(text, start, length).trim();
241 // If the entire text is empty or is made from whitespaces then we simply
242 // return
243 if (content.length() == 0) return;
244 contentStack.push(content);
245 if(DEBUG) Out.println(content);
246 } // characters
247
248 /** Utility method to create a resource and add to appropriate list.
249 * Parameters for the resource are pulled out of the current attribute
250 * list.
251 */
252 protected void createResource(String resourceTypeName, List resourceList)
253 throws GateSaxException
254 {
255 if(DEBUG) Out.prln(resourceTypeName + ": " + currentAttributeMap);
256 try {
257 resourceList.add(
258 Factory.createResource(
259 resourceTypeName, currentAttributeMap
260 )
261 );
262 } catch(ResourceInstantiationException e) {
263 throw new GateSaxException(
264 "Couldn't create resource for SYSTEM: " +
265 systemData.systemName + "; problem was: " + Strings.getNl() + e
266 );
267 }
268 } // createResource
269
270 /** Utility method to convert the current SAX attribute list to a
271 * FeatureMap
272 */
273 protected FeatureMap attributeListToParameterList() {
274 FeatureMap params = Factory.newFeatureMap();
275
276 // for each attribute of this element, add it to the param list
277 for(int i=0, len=currentAttributes.getLength(); i<len; i++) {
278 params.put(
279 currentAttributes.getQName(i), currentAttributes.getValue(i)
280 );
281 }
282
283 return params;
284 } // attributeListToParameterList
285
286 /** Called when the SAX parser encounts white space */
287 public void ignorableWhitespace(char ch[], int start, int length)
288 throws SAXException {
289 } // ignorableWhitespace
290
291 /** Called for parse errors. */
292 public void error(SAXParseException ex) throws SAXException {
293 _seh.error(ex);
294 } // error
295
296 /** Called for fatal errors. */
297 public void fatalError(SAXParseException ex) throws SAXException {
298 _seh.fatalError(ex);
299 } // fatalError
300
301 /** Called for warnings. */
302 public void warning(SAXParseException ex) throws SAXException {
303 _seh.warning(ex);
304 } // warning
305
306 } // ConfigXmlHandler
|