ConfigXmlHandler.java
001 /*
002  *  ConfigXmlHandler.java
003  *
004  *  Copyright (c) 1995-2012, 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 17653 2014-03-13 19:40:20Z markagreenwood $
015  */
016 
017 package gate.config;
018 
019 import gate.CreoleRegister;
020 import gate.Factory;
021 import gate.FeatureMap;
022 import gate.Gate;
023 import gate.util.GateException;
024 import gate.util.GateSaxException;
025 import gate.util.Out;
026 import gate.util.Strings;
027 import gate.xml.SimpleErrorHandler;
028 
029 import java.net.MalformedURLException;
030 import java.net.URL;
031 import java.util.Stack;
032 
033 import org.xml.sax.Attributes;
034 import org.xml.sax.SAXException;
035 import org.xml.sax.SAXParseException;
036 import org.xml.sax.helpers.DefaultHandler;
037 
038 
039 /** This is a SAX handler for processing <CODE>gate.xml</CODE> files.
040   */
041 public class ConfigXmlHandler extends DefaultHandler {
042 
043   /** A stack to stuff PCDATA onto for reading back at element ends.
044    *  (Probably redundant to have a stack as we only push one item
045    *  onto it. Probably. Ok, so I should check, but a) it works, b)
046    *  I'm bald already and c) life is short.)
047    */
048   private Stack<String> contentStack = new Stack<String>();
049 
050   /** The current element's attribute list */
051   private Attributes currentAttributes;
052 
053   /** A feature map representation of the current element's attribute list */
054   private FeatureMap currentAttributeMap;
055 
056   /** Debug flag */
057   private static final boolean DEBUG = false;
058 
059   /** The source URL of the config file being parsed. */
060   private URL sourceUrl;
061 
062   /** This object indicates what to do when the parser encounts an error*/
063   private SimpleErrorHandler _seh = new SimpleErrorHandler();
064 
065 
066   /** This is used to capture all data within two tags before calling the actual characters method */
067   private StringBuffer contentBuffer = new StringBuffer("");
068 
069   /** This is a variable that shows if characters have been read */
070   private boolean readCharacterStatus = false;
071 
072 
073   /** Construction */
074   public ConfigXmlHandler(URL configUrl) {
075     this.register = Gate.getCreoleRegister();
076     this.sourceUrl = configUrl;
077   // construction
078 
079   /** The register object that we add CREOLE directories to during parsing.
080     */
081   private CreoleRegister register;
082 
083   /** Called when the SAX parser encounts the beginning of the XML document */
084   @Override
085   public void startDocument() throws GateSaxException {
086     if(DEBUGOut.prln("start document");
087   // startDocument
088 
089   /** Called when the SAX parser encounts the end of the XML document */
090   @Override
091   public void endDocument() throws GateSaxException {
092     if(DEBUGOut.prln("end document");
093     if(! contentStack.isEmpty()) {
094       StringBuffer errorMessage =
095         new StringBuffer("document ended but element stack not empty:");
096       while(! contentStack.isEmpty())
097         errorMessage.append(Strings.getNl()+"  "+contentStack.pop());
098       throw new GateSaxException(errorMessage.toString());
099     }
100   // endDocument
101 
102   /** A verbose method for Attributes*/
103   private String attributes2String(Attributes atts){
104     StringBuffer strBuf = new StringBuffer("");
105     if (atts == nullreturn strBuf.toString();
106     for (int i = 0; i < atts.getLength(); i++) {
107      String attName  = atts.getQName(i);
108      String attValue = atts.getValue(i);
109      strBuf.append(" ");
110      strBuf.append(attName);
111      strBuf.append("=");
112      strBuf.append(attValue);
113     }// End for
114     return strBuf.toString();
115   }// attributes2String()
116 
117   /** Called when the SAX parser encounts the beginning of an XML element */
118   @Override
119   public void startElement (
120     String uri, String qName, String elementName, Attributes atts
121   throws SAXException {
122 
123     // call characterActions
124     if(readCharacterStatus) {
125       readCharacterStatus = false;
126       charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
127     }
128 
129     if(DEBUG) {
130       Out.pr("startElement: ");
131       Out.println(
132         elementName + " " +
133         attributes2String(atts)
134       );
135     }
136 
137     // record the attributes of this element for endElement()
138     currentAttributes = atts;
139     currentAttributeMap = attributeListToParameterList();
140 
141     if(elementName.toUpperCase().equals(Gate.getUserConfigElement())) {
142       Gate.getUserConfig().putAll(currentAttributeMap);
143     }
144 
145   // startElement
146 
147   /** Called when the SAX parser encounts the end of an XML element.
148     * This is actions happen.
149     */
150   @Override
151   public void endElement (String uri, String qName, String elementName)
152                                                       throws GateSaxException, SAXException {
153 
154      // call characterActions
155      if(readCharacterStatus) {
156        readCharacterStatus = false;
157        charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
158      }
159 
160     if(DEBUGOut.prln("endElement: " + elementName);
161 
162     //////////////////////////////////////////////////////////////////
163     if(elementName.toUpperCase().equals("GATE")) {
164 
165     //////////////////////////////////////////////////////////////////
166     else if(elementName.toUpperCase().equals("CREOLE-DIRECTORY")) {
167       String dirUrlName = contentStack.pop();
168       try {
169         register.registerDirectories(new URL(dirUrlName));
170       catch(MalformedURLException e) {
171         throw new GateSaxException("bad URL " + dirUrlName + e);
172       catch(GateException e) {
173         throw new GateSaxException("unable to register directory",e);
174       }
175 
176     //////////////////////////////////////////////////////////////////
177     else if(elementName.toUpperCase().equals("GATECONFIG")) {
178       // these are empty elements with attributes; nothing to do here
179 
180     //////////////////////////////////////////////////////////////////
181     else {
182       throw new GateSaxException(
183         "Unknown config data element: " + elementName +
184         "; encountered while parsing " + sourceUrl
185       );
186     }
187     //////////////////////////////////////////////////////////////////
188 
189   // endElement
190 
191   /** Called when the SAX parser encounts text (PCDATA) in the XML doc */
192   @Override
193   public void characters(char [] text,int start,int lengththrows SAXException {
194     if(!readCharacterStatus) {
195       contentBuffer = new StringBuffer(new String(text,start,length));
196     else {
197       contentBuffer.append(new String(text,start,length));
198     }
199     readCharacterStatus = true;
200   }
201 
202   /**
203     * This method is called when all characters between specific tags have been read completely
204     */
205 
206   public void charactersAction(char[] text, int start, int length)
207   throws SAXException {
208     // Get the trimmed text between elements
209     String content = new String(text, start, length).trim();
210     // If the entire text is empty or is made from whitespaces then we simply
211     // return
212     if (content.length() == 0return;
213     contentStack.push(content);
214     if(DEBUGOut.println(content);
215   // characters
216 
217   /** Utility method to convert the current SAX attribute list to a
218    *  FeatureMap
219    */
220   protected FeatureMap attributeListToParameterList() {
221     FeatureMap params = Factory.newFeatureMap();
222 
223     // for each attribute of this element, add it to the param list
224     for(int i=0, len=currentAttributes.getLength(); i<len; i++) {
225       params.put(
226         currentAttributes.getQName(i), currentAttributes.getValue(i)
227       );
228     }
229 
230     return params;
231   // attributeListToParameterList
232 
233   /** Called when the SAX parser encounts white space */
234   @Override
235   public void ignorableWhitespace(char ch[]int start, int length)
236   throws SAXException {
237   // ignorableWhitespace
238 
239   /** Called for parse errors. */
240   @Override
241   public void error(SAXParseException exthrows SAXException {
242     _seh.error(ex);
243   // error
244 
245   /** Called for fatal errors. */
246   @Override
247   public void fatalError(SAXParseException exthrows SAXException {
248     _seh.fatalError(ex);
249   // fatalError
250 
251   /** Called for warnings. */
252   @Override
253   public void warning(SAXParseException exthrows SAXException {
254     _seh.warning(ex);
255   // warning
256 
257 // ConfigXmlHandler