ConfigXmlHandler.java
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(DEBUGOut.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(DEBUGOut.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()+"  "+(StringcontentStack.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 == nullreturn 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(DEBUGOut.prln("endElement: " + elementName);
172 
173     //////////////////////////////////////////////////////////////////
174     if(elementName.toUpperCase().equals("GATE")) {
175 
176     //////////////////////////////////////////////////////////////////
177     else if(elementName.toUpperCase().equals("CREOLE-DIRECTORY")) {
178       String dirUrlName = (StringcontentStack.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 = (StringcontentStack.pop();
193 
194     //////////////////////////////////////////////////////////////////
195     else if(elementName.toUpperCase().equals("LR")) {
196       // create an LR and add it to the SystemData
197       createResource((StringcontentStack.pop(), systemData.lrList);
198 
199     //////////////////////////////////////////////////////////////////
200     else if(elementName.toUpperCase().equals("PR")) {
201       // create a PR and add it to the SystemData
202       createResource((StringcontentStack.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 lengththrows 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() == 0return;
244     contentStack.push(content);
245     if(DEBUGOut.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(DEBUGOut.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 exthrows SAXException {
293     _seh.error(ex);
294   // error
295 
296   /** Called for fatal errors. */
297   public void fatalError(SAXParseException exthrows SAXException {
298     _seh.fatalError(ex);
299   // fatalError
300 
301   /** Called for warnings. */
302   public void warning(SAXParseException exthrows SAXException {
303     _seh.warning(ex);
304   // warning
305 
306 // ConfigXmlHandler