1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.cosylab.application.state.impl;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Stack;
31
32 import javax.xml.transform.TransformerFactory;
33 import javax.xml.transform.sax.SAXResult;
34 import javax.xml.transform.sax.SAXSource;
35 import javax.xml.transform.stream.StreamResult;
36
37 import org.xml.sax.Attributes;
38 import org.xml.sax.ContentHandler;
39 import org.xml.sax.DTDHandler;
40 import org.xml.sax.EntityResolver;
41 import org.xml.sax.ErrorHandler;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xml.sax.SAXNotRecognizedException;
45 import org.xml.sax.SAXNotSupportedException;
46 import org.xml.sax.XMLReader;
47 import org.xml.sax.helpers.DefaultHandler;
48
49 import com.cosylab.application.state.State;
50 import com.cosylab.application.state.StateFactory;
51 import com.cosylab.application.state.StateStorage;
52
53 public class NewXMLStateStorage extends DefaultStateStorage {
54 private static final String ROOT_EL="states";
55 private static final String STATE_EL="state";
56
57 private static abstract class DefaultReader implements XMLReader {
58 ContentHandler ch;
59 DTDHandler dtd;
60 EntityResolver eRes;
61 ErrorHandler erh;
62 HashMap<String, Boolean> features;
63 {
64 features=new HashMap();
65 features.put("http://xml.org/sax/features/namespaces", Boolean.TRUE);
66 features.put("http://xml.org/sax/features/namespace-prefixes", Boolean.FALSE);
67 }
68
69 HashMap properties;
70
71 public ContentHandler getContentHandler() {
72 return null;
73 }
74 public DTDHandler getDTDHandler() {
75 return null;
76 }
77 public EntityResolver getEntityResolver() {
78 return null;
79 }
80 public ErrorHandler getErrorHandler() {
81 return null;
82 }
83 public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
84 return features.get(name);
85 }
86 public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
87 if (properties==null) throw new SAXNotRecognizedException(name+" is not in the properties map");
88 return properties.get(name);
89 }
90 public void parse(String systemId) throws IOException, SAXException {
91 parse(new InputSource(systemId));
92 }
93 public void setContentHandler(ContentHandler handler) {
94 ch=handler;
95 }
96 public void setDTDHandler(DTDHandler handler) {
97 dtd=handler;
98 }
99 public void setEntityResolver(EntityResolver resolver) {
100 eRes=resolver;
101 }
102 public void setErrorHandler(ErrorHandler handler) {
103 erh=handler;
104 }
105 public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
106 features.put(name, value);
107 }
108 public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
109 if (properties==null) properties=new HashMap<String, Object>();
110 properties.put(name, value);
111 }
112 }
113
114 private abstract static class AttrsImpl implements Attributes {
115 public int getIndex(String uri, String localName) {return getIndex(localName);}
116 public String getLocalName(int index) {return getQName(index);}
117 public String getType(String qName) {return getType(getIndex(qName));}
118 public String getType(String uri, String localName) {return getType(localName);}
119 public String getURI(int index) {return "";}
120 public String getValue(String qName) {return getValue(getIndex(qName));}
121 public String getValue(String uri, String localName) {return getValue(localName);}
122 public String getType(int index) { return (index<0 || index>=getLength())?null:"CDATA"; }
123 }
124
125 private static class MyAttributes extends AttrsImpl {
126 private String[] atrNames=new String[0];
127 private String[] atrVals=new String[0];
128
129 public MyAttributes() {
130 }
131
132 public MyAttributes(String[] atrNames, String[] atrVals){
133 this.atrNames=atrNames;
134 this.atrVals=atrVals;
135 }
136
137 public int getIndex(String qName) {
138 return atrNames.length;
139 }
140
141 public int getLength() {
142 return atrVals.length;
143 }
144
145 public String getQName(int index) {
146 return atrNames[index];
147 }
148
149 public String getValue(int index) {
150 return atrVals[index];
151 }
152 }
153
154 private static class MyReader extends DefaultReader {
155 List states;
156 public MyReader(List states) {
157 this.states=states;
158 }
159 public void parse(InputSource input) throws SAXException {
160 ch.startDocument();
161 ch.startElement("", ROOT_EL, ROOT_EL, new MyAttributes());
162
163 for (int i = 0; i < states.size(); i++) {
164 State s = (State)states.get(i);
165 storeState(STATE_EL, s);
166 }
167
168 ch.endElement("", ROOT_EL, ROOT_EL);
169 ch.endDocument();
170 }
171
172 private void storeState(String name, State s) throws SAXException{
173 Iterator iter = s.keySet().iterator();
174 ArrayList atrNames=new ArrayList();
175 ArrayList atrVals=new ArrayList();
176 ArrayList stNames=new ArrayList();
177 ArrayList stVals=new ArrayList();
178 while (iter.hasNext()) {
179 String key = (String)iter.next();
180 Object value = s.getObject(key);
181 if (value instanceof State) {
182 stNames.add(key);
183 stVals.add(value);
184 } else {
185 atrNames.add(key);
186 atrVals.add(String.valueOf(value));
187 }
188 }
189 String[] arAtrNames=(String[])atrNames.toArray(new String[atrNames.size()]);
190 String[] arAtrVals=(String[])atrVals.toArray(new String[atrVals.size()]);
191 ch.startElement("", name, name, new MyAttributes(arAtrNames,arAtrVals));
192 for (int i = 0; i < stNames.size(); i++) {
193 storeState((String)stNames.get(i), (State)stVals.get(i));
194 }
195 ch.endElement("", name, name);
196 }
197 }
198
199 private static class MyContentHandler extends DefaultHandler {
200 private List output;
201 private Stack current;
202 public MyContentHandler(List output) {
203 this.output=output;
204 this.current=new Stack();
205 }
206 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
207 if (current.isEmpty() && ROOT_EL.equals(localName)) return;
208 State newSt;
209 if (current.isEmpty()) {
210 newSt=StateFactory.createState();
211 output.add(newSt);
212 } else {
213 newSt=((State)current.peek()).createState(localName);
214 }
215 for (int i = 0; i < attributes.getLength(); i++) {
216 newSt.putString(attributes.getLocalName(i), attributes.getValue(i));
217 }
218 current.push(newSt);
219 }
220 public void endElement(String uri, String localName, String qName) throws SAXException {
221 if (current.isEmpty() && ROOT_EL.equals(localName)) return;
222 current.pop();
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235 public static final State[] loadStates(InputSource is)
236 throws IOException
237 {
238 ArrayList retList = new ArrayList();
239 loadStates(is, retList);
240
241 State[] ret = new State[retList.size()];
242 retList.toArray(ret);
243
244 return ret;
245 }
246
247 private static final void loadStates(InputSource is, List retStates)
248 throws IOException
249 {
250 try {
251 if (is == null || (is.getByteStream() == null && is.getCharacterStream()==null)) {
252 return;
253 }
254 SAXSource src=new SAXSource(is);
255 SAXResult res=new SAXResult(new MyContentHandler(retStates));
256 TransformerFactory.newInstance().newTransformer().transform(src, res);
257 } catch (Exception e) {
258 IOException exc = new IOException("Unable to read state from "
259 + is.getSystemId() + ": " + e.getMessage());
260 exc.initCause(e);
261 throw exc;
262 }
263 }
264
265 private static final void storeStates(List outStates, OutputStream os)
266 throws IOException
267 {
268 try {
269 SAXSource src=new SAXSource(new MyReader(outStates), new InputSource());
270 StreamResult res=new StreamResult(os);
271 TransformerFactory.newInstance().newTransformer().transform(src, res);
272
273 os.flush();
274 os.close();
275 } catch (Exception e) {
276 e.printStackTrace();
277
278 IOException exc = new IOException("Unable to store state! "
279 + e.getMessage());
280 exc.initCause(e);
281 throw exc;
282 }
283 }
284
285
286
287
288
289
290
291
292
293 public static final void storeStates(State[] outStates, OutputStream os)
294 throws IOException
295 {
296 storeStates(Arrays.asList(outStates), os);
297 }
298
299
300
301
302 public NewXMLStateStorage()
303 {
304 super();
305 }
306
307
308
309
310
311
312 public NewXMLStateStorage(StateStorage ss)
313 {
314 super(ss);
315 }
316
317
318
319
320
321
322
323
324 public void load(InputSource is) throws IOException
325 {
326 loadStates(is, states);
327 }
328
329
330
331
332
333
334
335
336 public void load(InputStream is) throws IOException
337 {
338 load(new InputSource(is));
339 }
340
341
342
343
344 public void load(String filePath, String applicationName)
345 throws IOException
346 {
347 if (delegate != null) {
348 delegate.load(filePath, applicationName);
349 addAll(delegate.getStates());
350
351 return;
352 }
353
354
355 InputStream is = getInputStream(filePath, applicationName + ".xml");
356
357 if (is != null) {
358 try {
359 load(is);
360 } catch (IOException e) {
361 IOException ex = new IOException("Failed to load from file '"
362 + filePath + "/" + applicationName + ".xml'");
363 ex.initCause(e);
364 throw ex;
365 }
366 }
367 }
368
369
370
371
372 public void store(OutputStream os) throws IOException
373 {
374 storeStates(states, os);
375 }
376
377
378
379
380 public void store(String filePath, String applicationName)
381 throws IOException
382 {
383 OutputStream os = getOutputStream(filePath, applicationName + ".xml");
384 store(os);
385 }
386
387 }