1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.hadoop.record;
20 
21 import java.io.InputStream;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 
25 import org.apache.hadoop.classification.InterfaceAudience;
26 import org.apache.hadoop.classification.InterfaceStability;
27 import org.xml.sax.*;
28 import org.xml.sax.helpers.DefaultHandler;
29 import javax.xml.parsers.SAXParserFactory;
30 import javax.xml.parsers.SAXParser;
31 
32 /**
33  * XML Deserializer.
34  *
35  * @deprecated Replaced by <a href="http://hadoop.apache.org/avro/">Avro</a>.
36  */
37 @Deprecated
38 @InterfaceAudience.Public
39 @InterfaceStability.Stable
40 public class XmlRecordInput implements RecordInput {
41 
42   static private class Value {
43     private String type;
44     private StringBuffer sb;
45 
Value(String t)46     public Value(String t) {
47       type = t;
48       sb = new StringBuffer();
49     }
addChars(char[] buf, int offset, int len)50     public void addChars(char[] buf, int offset, int len) {
51       sb.append(buf, offset, len);
52     }
getValue()53     public String getValue() { return sb.toString(); }
getType()54     public String getType() { return type; }
55   }
56 
57   private static class XMLParser extends DefaultHandler {
58     private boolean charsValid = false;
59 
60     private ArrayList<Value> valList;
61 
XMLParser(ArrayList<Value> vlist)62     private XMLParser(ArrayList<Value> vlist) {
63       valList = vlist;
64     }
65 
66     @Override
startDocument()67     public void startDocument() throws SAXException {}
68 
69     @Override
endDocument()70     public void endDocument() throws SAXException {}
71 
72     @Override
startElement(String ns, String sname, String qname, Attributes attrs)73     public void startElement(String ns,
74                              String sname,
75                              String qname,
76                              Attributes attrs) throws SAXException {
77       charsValid = false;
78       if ("boolean".equals(qname) ||
79           "i4".equals(qname) ||
80           "int".equals(qname) ||
81           "string".equals(qname) ||
82           "double".equals(qname) ||
83           "ex:i1".equals(qname) ||
84           "ex:i8".equals(qname) ||
85           "ex:float".equals(qname)) {
86         charsValid = true;
87         valList.add(new Value(qname));
88       } else if ("struct".equals(qname) ||
89                  "array".equals(qname)) {
90         valList.add(new Value(qname));
91       }
92     }
93 
94     @Override
endElement(String ns, String sname, String qname)95     public void endElement(String ns,
96                            String sname,
97                            String qname) throws SAXException {
98       charsValid = false;
99       if ("struct".equals(qname) ||
100           "array".equals(qname)) {
101         valList.add(new Value("/"+qname));
102       }
103     }
104 
105     @Override
characters(char buf[], int offset, int len)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
done()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
incr()129     public void incr() {}
130   }
131 
132   private ArrayList<Value> valList;
133   private int vLen;
134   private int vIdx;
135 
next()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 */
XmlRecordInput(InputStream in)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
readByte(String tag)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
readBool(String tag)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
readInt(String tag)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
readLong(String tag)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
readFloat(String tag)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
readDouble(String tag)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
readString(String tag)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
readBuffer(String tag)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
startRecord(String tag)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
endRecord(String tag)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
startVector(String tag)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
endVector(String tag)261   public void endVector(String tag) throws IOException {}
262 
263   @Override
startMap(String tag)264   public Index startMap(String tag) throws IOException {
265     return startVector(tag);
266   }
267 
268   @Override
endMap(String tag)269   public void endMap(String tag) throws IOException { endVector(tag); }
270 
271 }
272