source: josm/trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java@ 4685

Last change on this file since 4685 was 4685, checked in by bastiK, 13 years ago

session support (second part: "save as", see #4029)

still osm-data layer is the only implemented layer type

  • Property svn:eol-style set to native
File size: 7.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.session;
3
4import java.io.BufferedOutputStream;
5import java.io.File;
6import java.io.FileNotFoundException;
7import java.io.FileOutputStream;
8import java.io.IOException;
9import java.io.OutputStream;
10import java.io.OutputStreamWriter;
11import java.lang.reflect.Constructor;
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16import java.util.Set;
17import java.util.zip.ZipEntry;
18import java.util.zip.ZipOutputStream;
19
20import javax.xml.parsers.DocumentBuilder;
21import javax.xml.parsers.DocumentBuilderFactory;
22import javax.xml.parsers.ParserConfigurationException;
23import javax.xml.transform.OutputKeys;
24import javax.xml.transform.Transformer;
25import javax.xml.transform.TransformerException;
26import javax.xml.transform.TransformerFactory;
27import javax.xml.transform.dom.DOMSource;
28import javax.xml.transform.stream.StreamResult;
29
30import org.w3c.dom.Document;
31import org.w3c.dom.Element;
32import org.w3c.dom.Text;
33
34import org.openstreetmap.josm.gui.layer.Layer;
35import org.openstreetmap.josm.gui.layer.OsmDataLayer;
36import org.openstreetmap.josm.tools.MultiMap;
37import org.openstreetmap.josm.tools.Utils;
38
39public class SessionWriter {
40
41 private static Map<Class<? extends Layer>, Class<? extends SessionLayerExporter>> sessionLayerExporters =
42 new HashMap<Class<? extends Layer>, Class<? extends SessionLayerExporter>>();
43 static {
44 registerSessionLayerExporter(OsmDataLayer.class , OsmDataSessionExporter.class);
45 }
46
47 /**
48 * Register a session layer exporter.
49 *
50 * The exporter class must have an one-argument constructor with layerClass as formal parameter type.
51 */
52 public static void registerSessionLayerExporter(Class<? extends Layer> layerClass, Class<? extends SessionLayerExporter> exporter) {
53 sessionLayerExporters.put(layerClass, exporter);
54 }
55
56 public static SessionLayerExporter getSessionLayerExporter(Layer layer) {
57 Class<? extends Layer> layerClass = layer.getClass();
58 Class<? extends SessionLayerExporter> exporterClass = sessionLayerExporters.get(layerClass);
59 if (exporterClass == null) return null;
60 try {
61 @SuppressWarnings("unchecked")
62 Constructor<? extends SessionLayerExporter> constructor = (Constructor) exporterClass.getConstructor(layerClass);
63 return constructor.newInstance(layer);
64 } catch (Exception e) {
65 throw new RuntimeException(e);
66 }
67 }
68
69 private List<Layer> layers;
70 private Map<Layer, SessionLayerExporter> exporters;
71 private MultiMap<Layer, Layer> dependencies;
72 private boolean zip;
73
74 private ZipOutputStream zipOut;
75
76 public SessionWriter(List<Layer> layers, Map<Layer, SessionLayerExporter> exporters,
77 MultiMap<Layer, Layer> dependencies, boolean zip) {
78 this.layers = layers;
79 this.exporters = exporters;
80 this.dependencies = dependencies;
81 this.zip = zip;
82 }
83
84 public class ExportSupport {
85 private Document doc;
86 private int layerIndex;
87
88 public ExportSupport(Document doc, int layerIndex) {
89 this.doc = doc;
90 this.layerIndex = layerIndex;
91 }
92
93 public Element createElement(String name) {
94 return doc.createElement(name);
95 }
96
97 public Text createTextNode(String text) {
98 return doc.createTextNode(text);
99 }
100
101 public int getLayerIndex() {
102 return layerIndex;
103 }
104
105 /**
106 * Create a file in the zip archive.
107 *
108 * @return never close the output stream, but make sure to flush buffers
109 */
110 public OutputStream getOutputStreamZip(String zipPath) throws IOException {
111 if (!isZip()) throw new RuntimeException();
112 ZipEntry entry = new ZipEntry(zipPath);
113 zipOut.putNextEntry(entry);
114 return zipOut;
115 }
116
117 public boolean isZip() {
118 return zip;
119 }
120 }
121
122 public Document createJosDocument() throws IOException {
123 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
124 builderFactory.setValidating(false);
125 builderFactory.setNamespaceAware(true);
126 DocumentBuilder builder = null;
127 try {
128 builder = builderFactory.newDocumentBuilder();
129 } catch (ParserConfigurationException e) {
130 throw new RuntimeException(e);
131 }
132 Document doc = builder.newDocument();
133
134 Element root = doc.createElement("josm-session");
135 root.setAttribute("version", "0.1");
136 doc.appendChild(root);
137
138 Element layersEl = doc.createElement("layers");
139 root.appendChild(layersEl);
140
141 for (int index=0; index<layers.size(); ++index) {
142 Layer layer = layers.get(index);
143 SessionLayerExporter exporter = exporters.get(layer);
144 ExportSupport support = new ExportSupport(doc, index+1);
145 Element el = exporter.export(support);
146 el.setAttribute("index", Integer.toString(index+1));
147 el.setAttribute("name", layer.getName());
148 Set<Layer> deps = dependencies.get(layer);
149 if (deps.size() > 0) {
150 List<Integer> depsInt = new ArrayList<Integer>();
151 for (Layer depLayer : deps) {
152 int depIndex = layers.indexOf(depLayer);
153 if (depIndex == -1) throw new AssertionError();
154 depsInt.add(depIndex+1);
155 }
156 el.setAttribute("depends", Utils.join(",", depsInt));
157 }
158 layersEl.appendChild(el);
159 }
160 return doc;
161 }
162
163 public void writeJos(Document doc, OutputStream out) throws IOException {
164 try {
165 OutputStreamWriter writer = new OutputStreamWriter(out, "utf-8");
166 writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
167 TransformerFactory transfac = TransformerFactory.newInstance();
168 Transformer trans = transfac.newTransformer();
169 trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
170 trans.setOutputProperty(OutputKeys.INDENT, "yes");
171 trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
172 StreamResult result = new StreamResult(writer);
173 DOMSource source = new DOMSource(doc);
174 trans.transform(source, result);
175 } catch (TransformerException e) {
176 throw new RuntimeException(e);
177 }
178 }
179
180 public void write(File f) throws IOException {
181 OutputStream out = null;
182 try {
183 out = new FileOutputStream(f);
184 } catch (FileNotFoundException e) {
185 throw new IOException(e);
186 }
187 write(out);
188 }
189
190 public void write (OutputStream out) throws IOException {
191 if (zip) {
192 zipOut = new ZipOutputStream(new BufferedOutputStream(out));
193 }
194 Document doc = createJosDocument(); // as side effect, files may be added to zipOut
195 if (zip) {
196 ZipEntry entry = new ZipEntry("session.jos");
197 zipOut.putNextEntry(entry);
198 writeJos(doc, zipOut);
199 zipOut.close();
200 } else {
201 writeJos(doc, new BufferedOutputStream(out));
202 }
203 Utils.close(out);
204 }
205}
Note: See TracBrowser for help on using the repository browser.