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    
019    package org.apache.hadoop.record;
020    
021    import java.io.InputStream;
022    import java.io.IOException;
023    import java.util.ArrayList;
024    
025    import org.apache.hadoop.classification.InterfaceAudience;
026    import org.apache.hadoop.classification.InterfaceStability;
027    import org.xml.sax.*;
028    import org.xml.sax.helpers.DefaultHandler;
029    import javax.xml.parsers.SAXParserFactory;
030    import 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
040    public 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    }