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    @Override
067    public void startDocument() throws SAXException {}
068        
069    @Override
070    public void endDocument() throws SAXException {}
071        
072    @Override
073    public void startElement(String ns,
074                             String sname,
075                             String qname,
076                             Attributes attrs) throws SAXException {
077      charsValid = false;
078      if ("boolean".equals(qname) ||
079          "i4".equals(qname) ||
080          "int".equals(qname) ||
081          "string".equals(qname) ||
082          "double".equals(qname) ||
083          "ex:i1".equals(qname) ||
084          "ex:i8".equals(qname) ||
085          "ex:float".equals(qname)) {
086        charsValid = true;
087        valList.add(new Value(qname));
088      } else if ("struct".equals(qname) ||
089                 "array".equals(qname)) {
090        valList.add(new Value(qname));
091      }
092    }
093        
094    @Override
095    public void endElement(String ns,
096                           String sname,
097                           String qname) throws SAXException {
098      charsValid = false;
099      if ("struct".equals(qname) ||
100          "array".equals(qname)) {
101        valList.add(new Value("/"+qname));
102      }
103    }
104        
105    @Override
106    public void characters(char buf[], int offset, int len)
107      throws SAXException {
108      if (charsValid) {
109        Value v = valList.get(valList.size()-1);
110        v.addChars(buf, offset, len);
111      }
112    }
113        
114  }
115    
116  private class XmlIndex implements Index {
117    @Override
118    public boolean done() {
119      Value v = valList.get(vIdx);
120      if ("/array".equals(v.getType())) {
121        valList.set(vIdx, null);
122        vIdx++;
123        return true;
124      } else {
125        return false;
126      }
127    }
128    @Override
129    public void incr() {}
130  }
131    
132  private ArrayList<Value> valList;
133  private int vLen;
134  private int vIdx;
135    
136  private Value next() throws IOException {
137    if (vIdx < vLen) {
138      Value v = valList.get(vIdx);
139      valList.set(vIdx, null);
140      vIdx++;
141      return v;
142    } else {
143      throw new IOException("Error in deserialization.");
144    }
145  }
146    
147  /** Creates a new instance of XmlRecordInput */
148  public XmlRecordInput(InputStream in) {
149    try{
150      valList = new ArrayList<Value>();
151      DefaultHandler handler = new XMLParser(valList);
152      SAXParserFactory factory = SAXParserFactory.newInstance();
153      SAXParser parser = factory.newSAXParser();
154      parser.parse(in, handler);
155      vLen = valList.size();
156      vIdx = 0;
157    } catch (Exception ex) {
158      throw new RuntimeException(ex);
159    }
160  }
161    
162  @Override
163  public byte readByte(String tag) throws IOException {
164    Value v = next();
165    if (!"ex:i1".equals(v.getType())) {
166      throw new IOException("Error deserializing "+tag+".");
167    }
168    return Byte.parseByte(v.getValue());
169  }
170    
171  @Override
172  public boolean readBool(String tag) throws IOException {
173    Value v = next();
174    if (!"boolean".equals(v.getType())) {
175      throw new IOException("Error deserializing "+tag+".");
176    }
177    return "1".equals(v.getValue());
178  }
179    
180  @Override
181  public int readInt(String tag) throws IOException {
182    Value v = next();
183    if (!"i4".equals(v.getType()) &&
184        !"int".equals(v.getType())) {
185      throw new IOException("Error deserializing "+tag+".");
186    }
187    return Integer.parseInt(v.getValue());
188  }
189    
190  @Override
191  public long readLong(String tag) throws IOException {
192    Value v = next();
193    if (!"ex:i8".equals(v.getType())) {
194      throw new IOException("Error deserializing "+tag+".");
195    }
196    return Long.parseLong(v.getValue());
197  }
198    
199  @Override
200  public float readFloat(String tag) throws IOException {
201    Value v = next();
202    if (!"ex:float".equals(v.getType())) {
203      throw new IOException("Error deserializing "+tag+".");
204    }
205    return Float.parseFloat(v.getValue());
206  }
207    
208  @Override
209  public double readDouble(String tag) throws IOException {
210    Value v = next();
211    if (!"double".equals(v.getType())) {
212      throw new IOException("Error deserializing "+tag+".");
213    }
214    return Double.parseDouble(v.getValue());
215  }
216    
217  @Override
218  public String readString(String tag) throws IOException {
219    Value v = next();
220    if (!"string".equals(v.getType())) {
221      throw new IOException("Error deserializing "+tag+".");
222    }
223    return Utils.fromXMLString(v.getValue());
224  }
225    
226  @Override
227  public Buffer readBuffer(String tag) throws IOException {
228    Value v = next();
229    if (!"string".equals(v.getType())) {
230      throw new IOException("Error deserializing "+tag+".");
231    }
232    return Utils.fromXMLBuffer(v.getValue());
233  }
234    
235  @Override
236  public void startRecord(String tag) throws IOException {
237    Value v = next();
238    if (!"struct".equals(v.getType())) {
239      throw new IOException("Error deserializing "+tag+".");
240    }
241  }
242    
243  @Override
244  public void endRecord(String tag) throws IOException {
245    Value v = next();
246    if (!"/struct".equals(v.getType())) {
247      throw new IOException("Error deserializing "+tag+".");
248    }
249  }
250    
251  @Override
252  public Index startVector(String tag) throws IOException {
253    Value v = next();
254    if (!"array".equals(v.getType())) {
255      throw new IOException("Error deserializing "+tag+".");
256    }
257    return new XmlIndex();
258  }
259    
260  @Override
261  public void endVector(String tag) throws IOException {}
262    
263  @Override
264  public Index startMap(String tag) throws IOException {
265    return startVector(tag);
266  }
267    
268  @Override
269  public void endMap(String tag) throws IOException { endVector(tag); }
270
271}