source: josm/trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java@ 2474

Last change on this file since 2474 was 2017, checked in by Gubaer, 15 years ago

removed OptionPaneUtil
cleanup of deprecated Layer API
cleanup of deprecated APIs in OsmPrimitive and Way
cleanup of imports

  • Property svn:eol-style set to native
File size: 9.9 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.tools;
3
4import java.io.Reader;
5import java.lang.reflect.Field;
6import java.lang.reflect.Method;
7import java.lang.reflect.Modifier;
8import java.util.HashMap;
9import java.util.Iterator;
10import java.util.Map;
11import java.util.NoSuchElementException;
12import java.util.Stack;
13import java.util.concurrent.ArrayBlockingQueue;
14import java.util.concurrent.BlockingQueue;
15
16import javax.xml.parsers.SAXParserFactory;
17
18import org.xml.sax.Attributes;
19import org.xml.sax.InputSource;
20import org.xml.sax.SAXException;
21import org.xml.sax.helpers.DefaultHandler;
22
23/**
24 * An helper class that reads from a XML stream into specific objects.
25 *
26 * @author Imi
27 */
28public class XmlObjectParser implements Iterable<Object> {
29
30 public static final String lang = LanguageInfo.getLanguageCodeXML();
31 public static class Uniform<T> implements Iterable<T>{
32 private Iterator<Object> iterator;
33 /**
34 * @param klass This has to be specified since generics are ereased from
35 * class files so the JVM cannot deduce T itself.
36 */
37 public Uniform(Reader input, String tagname, Class<T> klass) {
38 XmlObjectParser parser = new XmlObjectParser();
39 parser.map(tagname, klass);
40 parser.start(input);
41 iterator = parser.iterator();
42 }
43 public Iterator<T> iterator() {
44 return new Iterator<T>(){
45 public boolean hasNext() {return iterator.hasNext();}
46 @SuppressWarnings("unchecked") public T next() {return (T)iterator.next();}
47 public void remove() {iterator.remove();}
48 };
49 }
50 }
51
52 private class Parser extends DefaultHandler {
53 Stack<Object> current = new Stack<Object>();
54 String characters = "";
55 @Override public void startElement(String ns, String lname, String qname, Attributes a) throws SAXException {
56 if (mapping.containsKey(qname)) {
57 Class<?> klass = mapping.get(qname).klass;
58 try {
59 current.push(klass.newInstance());
60 } catch (Exception e) {
61 throw new SAXException(e);
62 }
63 for (int i = 0; i < a.getLength(); ++i)
64 setValue(a.getQName(i), a.getValue(i));
65 if (mapping.get(qname).onStart)
66 report();
67 if (mapping.get(qname).both)
68 {
69 try {
70 queue.put(current.peek());
71 } catch (InterruptedException e) {
72 }
73 }
74 }
75 }
76 @Override public void endElement(String ns, String lname, String qname) throws SAXException {
77 if (mapping.containsKey(qname) && !mapping.get(qname).onStart)
78 report();
79 else if (characters != null && !current.isEmpty()) {
80 setValue(qname, characters.trim());
81 characters = "";
82 }
83 }
84 @Override public void characters(char[] ch, int start, int length) {
85 String s = new String(ch, start, length);
86 characters += s;
87 }
88
89 private void report() {
90 try {
91 queue.put(current.pop());
92 } catch (InterruptedException e) {
93 }
94 characters = "";
95 }
96
97 private Object getValueForClass(Class<?> klass, String value) {
98 if (klass == Boolean.TYPE)
99 return parseBoolean(value);
100 else if (klass == Integer.TYPE || klass == Long.TYPE)
101 return Long.parseLong(value);
102 else if (klass == Float.TYPE || klass == Double.TYPE)
103 return Double.parseDouble(value);
104 return value;
105 }
106
107 private void setValue(String fieldName, String value) throws SAXException {
108 if (fieldName.equals("class") || fieldName.equals("default") || fieldName.equals("throw") || fieldName.equals("new") || fieldName.equals("null"))
109 fieldName += "_";
110 try {
111 Object c = current.peek();
112 Field f = null;
113 try {
114 f = c.getClass().getField(fieldName);
115 } catch (NoSuchFieldException e) {
116 if(fieldName.startsWith(lang))
117 {
118 String locfieldName = "locale_" +
119 fieldName.substring(lang.length());
120 try {
121 f = c.getClass().getField(locfieldName);
122 } catch (NoSuchFieldException ex) {
123 }
124 }
125 }
126 if (f != null && Modifier.isPublic(f.getModifiers()))
127 f.set(c, getValueForClass(f.getType(), value));
128 else {
129 if(fieldName.startsWith(lang))
130 {
131 int l = lang.length();
132 fieldName = "set" + fieldName.substring(l,l+1).toUpperCase() + fieldName.substring(l+1);
133 }
134 else
135 {
136 fieldName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
137 }
138 Method[] methods = c.getClass().getDeclaredMethods();
139 for (Method m : methods) {
140 if (m.getName().equals(fieldName) && m.getParameterTypes().length == 1) {
141 m.invoke(c, new Object[]{getValueForClass(m.getParameterTypes()[0], value)});
142 return;
143 }
144 }
145 }
146 } catch (Exception e) {
147 e.printStackTrace(); // SAXException does not dump inner exceptions.
148 throw new SAXException(e);
149 }
150 }
151 private boolean parseBoolean(String s) {
152 return s != null &&
153 !s.equals("0") &&
154 !s.startsWith("off") &&
155 !s.startsWith("false") &&
156 !s.startsWith("no");
157 }
158 }
159
160 private static class Entry {
161 Class<?> klass;
162 boolean onStart;
163 boolean both;
164 public Entry(Class<?> klass, boolean onStart, boolean both) {
165 super();
166 this.klass = klass;
167 this.onStart = onStart;
168 this.both = both;
169 }
170 }
171
172 private Map<String, Entry> mapping = new HashMap<String, Entry>();
173 private Parser parser;
174
175 /**
176 * The queue of already parsed items from the parsing thread.
177 */
178 private BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(10);
179
180 /**
181 * This stores one item retrieved from the queue to give hasNext a chance.
182 * So this is also the object that will be returned on the next call to next().
183 */
184 private Object lookAhead = null;
185
186 /**
187 * This object represent the end of the stream (null is not allowed as
188 * member in class Queue).
189 */
190 private Object EOS = new Object();
191
192 public XmlObjectParser() {
193 parser = new Parser();
194 }
195
196 public Iterable<Object> start(final Reader in) {
197 new Thread("XML Reader"){
198 @Override public void run() {
199 try {
200 SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(in), parser);
201 } catch (Exception e) {
202 try {
203 queue.put(e);
204 } catch (InterruptedException e1) {
205 }
206 }
207 parser = null;
208 try {
209 queue.put(EOS);
210 } catch (InterruptedException e) {
211 }
212 }
213 }.start();
214 return this;
215 }
216
217 public void map(String tagName, Class<?> klass) {
218 mapping.put(tagName, new Entry(klass,false,false));
219 }
220
221 public void mapOnStart(String tagName, Class<?> klass) {
222 mapping.put(tagName, new Entry(klass,true,false));
223 }
224
225 public void mapBoth(String tagName, Class<?> klass) {
226 mapping.put(tagName, new Entry(klass,false,true));
227 }
228
229 /**
230 * @return The next object from the xml stream or <code>null</code>,
231 * if no more objects.
232 */
233 public Object next() throws SAXException {
234 fillLookAhead();
235 if (lookAhead == EOS)
236 throw new NoSuchElementException();
237 Object o = lookAhead;
238 lookAhead = null;
239 return o;
240 }
241
242 private void fillLookAhead() throws SAXException {
243 if (lookAhead != null)
244 return;
245 try {
246 lookAhead = queue.take();
247 if (lookAhead instanceof SAXException)
248 throw (SAXException)lookAhead;
249 else if (lookAhead instanceof RuntimeException)
250 throw (RuntimeException)lookAhead;
251 else if (lookAhead instanceof Exception)
252 throw new SAXException((Exception)lookAhead);
253 } catch (InterruptedException e) {
254 throw new RuntimeException("XmlObjectParser must not be interrupted.", e);
255 }
256 }
257
258 public boolean hasNext() throws SAXException {
259 fillLookAhead();
260 return lookAhead != EOS;
261 }
262
263 public Iterator<Object> iterator() {
264 return new Iterator<Object>(){
265 public boolean hasNext() {
266 try {
267 return XmlObjectParser.this.hasNext();
268 } catch (SAXException e) {
269 e.printStackTrace();
270 throw new RuntimeException(e);
271 }
272 }
273 public Object next() {
274 try {
275 return XmlObjectParser.this.next();
276 } catch (SAXException e) {
277 e.printStackTrace();
278 throw new RuntimeException(e);
279 }
280 }
281 public void remove() {
282 throw new UnsupportedOperationException();
283 }
284 };
285 }
286}
Note: See TracBrowser for help on using the repository browser.