001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.record;
020
021import java.io.InputStream;
022import java.io.IOException;
023import java.util.ArrayList;
024
025import org.apache.hadoop.classification.InterfaceAudience;
026import org.apache.hadoop.classification.InterfaceStability;
027import org.xml.sax.*;
028import org.xml.sax.helpers.DefaultHandler;
029import javax.xml.parsers.SAXParserFactory;
030import javax.xml.parsers.SAXParser;
031
032/**
033 * XML Deserializer.
034 * 
035 * @deprecated Replaced by <a href="https://hadoop.apache.org/avro/">Avro</a>.
036 */
037@Deprecated
038@InterfaceAudience.Public
039@InterfaceStability.Stable
040public class XmlRecordInput implements RecordInput {
041    
042  static private class Value {
043    private String type;
044    private StringBuffer sb;
045        
046    public Value(String t) {
047      type = t;
048      sb = new StringBuffer();
049    }
050    public void addChars(char[] buf, int offset, int len) {
051      sb.append(buf, offset, len);
052    }
053    public String getValue() { return sb.toString(); }
054    public String getType() { return type; }
055  }
056    
057  private static class XMLParser extends DefaultHandler {
058    private boolean charsValid = false;
059        
060    private ArrayList<Value> valList;
061        
062    private XMLParser(ArrayList<Value> vlist) {
063      valList = vlist;
064    }
065        
066    public void startDocument() throws SAXException {}
067        
068    public void endDocument() throws SAXException {}
069        
070    public void startElement(String ns,
071                             String sname,
072                             String qname,
073                             Attributes attrs) throws SAXException {
074      charsValid = false;
075      if ("boolean".equals(qname) ||
076          "i4".equals(qname) ||
077          "int".equals(qname) ||
078          "string".equals(qname) ||
079          "double".equals(qname) ||
080          "ex:i1".equals(qname) ||
081          "ex:i8".equals(qname) ||
082          "ex:float".equals(qname)) {
083        charsValid = true;
084        valList.add(new Value(qname));
085      } else if ("struct".equals(qname) ||
086                 "array".equals(qname)) {
087        valList.add(new Value(qname));
088      }
089    }
090        
091    public void endElement(String ns,
092                           String sname,
093                           String qname) throws SAXException {
094      charsValid = false;
095      if ("struct".equals(qname) ||
096          "array".equals(qname)) {
097        valList.add(new Value("/"+qname));
098      }
099    }
100        
101    public void characters(char buf[], int offset, int len)
102      throws SAXException {
103      if (charsValid) {
104        Value v = valList.get(valList.size()-1);
105        v.addChars(buf, offset, len);
106      }
107    }
108        
109  }
110    
111  private class XmlIndex implements Index {
112    public boolean done() {
113      Value v = valList.get(vIdx);
114      if ("/array".equals(v.getType())) {
115        valList.set(vIdx, null);
116        vIdx++;
117        return true;
118      } else {
119        return false;
120      }
121    }
122    public void incr() {}
123  }
124    
125  private ArrayList<Value> valList;
126  private int vLen;
127  private int vIdx;
128    
129  private Value next() throws IOException {
130    if (vIdx < vLen) {
131      Value v = valList.get(vIdx);
132      valList.set(vIdx, null);
133      vIdx++;
134      return v;
135    } else {
136      throw new IOException("Error in deserialization.");
137    }
138  }
139    
140  /** Creates a new instance of XmlRecordInput */
141  public XmlRecordInput(InputStream in) {
142    try{
143      valList = new ArrayList<Value>();
144      DefaultHandler handler = new XMLParser(valList);
145      SAXParserFactory factory = SAXParserFactory.newInstance();
146      SAXParser parser = factory.newSAXParser();
147      parser.parse(in, handler);
148      vLen = valList.size();
149      vIdx = 0;
150    } catch (Exception ex) {
151      throw new RuntimeException(ex);
152    }
153  }
154    
155  public byte readByte(String tag) throws IOException {
156    Value v = next();
157    if (!"ex:i1".equals(v.getType())) {
158      throw new IOException("Error deserializing "+tag+".");
159    }
160    return Byte.parseByte(v.getValue());
161  }
162    
163  public boolean readBool(String tag) throws IOException {
164    Value v = next();
165    if (!"boolean".equals(v.getType())) {
166      throw new IOException("Error deserializing "+tag+".");
167    }
168    return "1".equals(v.getValue());
169  }
170    
171  public int readInt(String tag) throws IOException {
172    Value v = next();
173    if (!"i4".equals(v.getType()) &&
174        !"int".equals(v.getType())) {
175      throw new IOException("Error deserializing "+tag+".");
176    }
177    return Integer.parseInt(v.getValue());
178  }
179    
180  public long readLong(String tag) throws IOException {
181    Value v = next();
182    if (!"ex:i8".equals(v.getType())) {
183      throw new IOException("Error deserializing "+tag+".");
184    }
185    return Long.parseLong(v.getValue());
186  }
187    
188  public float readFloat(String tag) throws IOException {
189    Value v = next();
190    if (!"ex:float".equals(v.getType())) {
191      throw new IOException("Error deserializing "+tag+".");
192    }
193    return Float.parseFloat(v.getValue());
194  }
195    
196  public double readDouble(String tag) throws IOException {
197    Value v = next();
198    if (!"double".equals(v.getType())) {
199      throw new IOException("Error deserializing "+tag+".");
200    }
201    return Double.parseDouble(v.getValue());
202  }
203    
204  public String readString(String tag) throws IOException {
205    Value v = next();
206    if (!"string".equals(v.getType())) {
207      throw new IOException("Error deserializing "+tag+".");
208    }
209    return Utils.fromXMLString(v.getValue());
210  }
211    
212  public Buffer readBuffer(String tag) throws IOException {
213    Value v = next();
214    if (!"string".equals(v.getType())) {
215      throw new IOException("Error deserializing "+tag+".");
216    }
217    return Utils.fromXMLBuffer(v.getValue());
218  }
219    
220  public void startRecord(String tag) throws IOException {
221    Value v = next();
222    if (!"struct".equals(v.getType())) {
223      throw new IOException("Error deserializing "+tag+".");
224    }
225  }
226    
227  public void endRecord(String tag) throws IOException {
228    Value v = next();
229    if (!"/struct".equals(v.getType())) {
230      throw new IOException("Error deserializing "+tag+".");
231    }
232  }
233    
234  public Index startVector(String tag) throws IOException {
235    Value v = next();
236    if (!"array".equals(v.getType())) {
237      throw new IOException("Error deserializing "+tag+".");
238    }
239    return new XmlIndex();
240  }
241    
242  public void endVector(String tag) throws IOException {}
243    
244  public Index startMap(String tag) throws IOException {
245    return startVector(tag);
246  }
247    
248  public void endMap(String tag) throws IOException { endVector(tag); }
249
250}