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

Last change on this file since 5505 was 5505, checked in by bastiK, 12 years ago

add session support for geoimage layers (see #4029)

  • Property svn:eol-style set to native
File size: 8.7 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.openstreetmap.josm.gui.layer.GpxLayer;
31import org.openstreetmap.josm.gui.layer.Layer;
32import org.openstreetmap.josm.gui.layer.OsmDataLayer;
33import org.openstreetmap.josm.gui.layer.TMSLayer;
34import org.openstreetmap.josm.gui.layer.WMSLayer;
35import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
36import org.openstreetmap.josm.tools.MultiMap;
37import org.openstreetmap.josm.tools.Utils;
38import org.w3c.dom.Document;
39import org.w3c.dom.Element;
40import org.w3c.dom.Text;
41
42public class SessionWriter {
43
44 private static Map<Class<? extends Layer>, Class<? extends SessionLayerExporter>> sessionLayerExporters =
45 new HashMap<Class<? extends Layer>, Class<? extends SessionLayerExporter>>();
46 static {
47 registerSessionLayerExporter(OsmDataLayer.class , OsmDataSessionExporter.class);
48 registerSessionLayerExporter(TMSLayer.class , ImagerySessionExporter.class);
49 registerSessionLayerExporter(WMSLayer.class , ImagerySessionExporter.class);
50 registerSessionLayerExporter(GpxLayer.class , GpxTracksSessionExporter.class);
51 registerSessionLayerExporter(GeoImageLayer.class , GeoImageSessionExporter.class);
52 }
53
54 /**
55 * Register a session layer exporter.
56 *
57 * The exporter class must have an one-argument constructor with layerClass as formal parameter type.
58 */
59 public static void registerSessionLayerExporter(Class<? extends Layer> layerClass, Class<? extends SessionLayerExporter> exporter) {
60 sessionLayerExporters.put(layerClass, exporter);
61 }
62
63 public static SessionLayerExporter getSessionLayerExporter(Layer layer) {
64 Class<? extends Layer> layerClass = layer.getClass();
65 Class<? extends SessionLayerExporter> exporterClass = sessionLayerExporters.get(layerClass);
66 if (exporterClass == null) return null;
67 try {
68 @SuppressWarnings("unchecked")
69 Constructor<? extends SessionLayerExporter> constructor = (Constructor) exporterClass.getConstructor(layerClass);
70 return constructor.newInstance(layer);
71 } catch (Exception e) {
72 throw new RuntimeException(e);
73 }
74 }
75
76 private List<Layer> layers;
77 private Map<Layer, SessionLayerExporter> exporters;
78 private MultiMap<Layer, Layer> dependencies;
79 private boolean zip;
80
81 private ZipOutputStream zipOut;
82
83 public SessionWriter(List<Layer> layers, Map<Layer, SessionLayerExporter> exporters,
84 MultiMap<Layer, Layer> dependencies, boolean zip) {
85 this.layers = layers;
86 this.exporters = exporters;
87 this.dependencies = dependencies;
88 this.zip = zip;
89 }
90
91 /**
92 * A class that provides some context for the individual {@link SessionLayerExporter}
93 * when doing the export.
94 */
95 public class ExportSupport {
96 private Document doc;
97 private int layerIndex;
98
99 public ExportSupport(Document doc, int layerIndex) {
100 this.doc = doc;
101 this.layerIndex = layerIndex;
102 }
103
104 public Element createElement(String name) {
105 return doc.createElement(name);
106 }
107
108 public Text createTextNode(String text) {
109 return doc.createTextNode(text);
110 }
111
112 /**
113 * Get the index of the layer that is currently exported.
114 * @return the index of the layer that is currently exported
115 */
116 public int getLayerIndex() {
117 return layerIndex;
118 }
119
120 /**
121 * Create a file inside the zip archive.
122 *
123 * @param zipPath the path inside the zip archive, e.g. "layers/03/data.xml"
124 * @return the OutputStream you can write to. Never close the returned
125 * output stream, but make sure to flush buffers.
126 */
127 public OutputStream getOutputStreamZip(String zipPath) throws IOException {
128 if (!isZip()) throw new RuntimeException();
129 ZipEntry entry = new ZipEntry(zipPath);
130 zipOut.putNextEntry(entry);
131 return zipOut;
132 }
133
134 /**
135 * Check, if the session is exported as a zip archive.
136 *
137 * @return true, if the session is exported as a zip archive (.joz file
138 * extension). It will always return true, if one of the
139 * {@link SessionLayerExporter} returns true for the
140 * {@link SessionLayerExporter#requiresZip()} method. Otherwise, the
141 * user can decide in the file chooser dialog.
142 */
143 public boolean isZip() {
144 return zip;
145 }
146 }
147
148 public Document createJosDocument() throws IOException {
149 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
150 builderFactory.setValidating(false);
151 builderFactory.setNamespaceAware(true);
152 DocumentBuilder builder = null;
153 try {
154 builder = builderFactory.newDocumentBuilder();
155 } catch (ParserConfigurationException e) {
156 throw new RuntimeException(e);
157 }
158 Document doc = builder.newDocument();
159
160 Element root = doc.createElement("josm-session");
161 root.setAttribute("version", "0.1");
162 doc.appendChild(root);
163
164 Element layersEl = doc.createElement("layers");
165 root.appendChild(layersEl);
166
167 for (int index=0; index<layers.size(); ++index) {
168 Layer layer = layers.get(index);
169 SessionLayerExporter exporter = exporters.get(layer);
170 ExportSupport support = new ExportSupport(doc, index+1);
171 Element el = exporter.export(support);
172 el.setAttribute("index", Integer.toString(index+1));
173 el.setAttribute("name", layer.getName());
174 Set<Layer> deps = dependencies.get(layer);
175 if (deps.size() > 0) {
176 List<Integer> depsInt = new ArrayList<Integer>();
177 for (Layer depLayer : deps) {
178 int depIndex = layers.indexOf(depLayer);
179 if (depIndex == -1) throw new AssertionError();
180 depsInt.add(depIndex+1);
181 }
182 el.setAttribute("depends", Utils.join(",", depsInt));
183 }
184 layersEl.appendChild(el);
185 }
186 return doc;
187 }
188
189 public void writeJos(Document doc, OutputStream out) throws IOException {
190 try {
191 OutputStreamWriter writer = new OutputStreamWriter(out, "utf-8");
192 writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
193 TransformerFactory transfac = TransformerFactory.newInstance();
194 Transformer trans = transfac.newTransformer();
195 trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
196 trans.setOutputProperty(OutputKeys.INDENT, "yes");
197 trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
198 StreamResult result = new StreamResult(writer);
199 DOMSource source = new DOMSource(doc);
200 trans.transform(source, result);
201 } catch (TransformerException e) {
202 throw new RuntimeException(e);
203 }
204 }
205
206 public void write(File f) throws IOException {
207 OutputStream out = null;
208 try {
209 out = new FileOutputStream(f);
210 } catch (FileNotFoundException e) {
211 throw new IOException(e);
212 }
213 write(out);
214 }
215
216 public void write (OutputStream out) throws IOException {
217 if (zip) {
218 zipOut = new ZipOutputStream(new BufferedOutputStream(out));
219 }
220 Document doc = createJosDocument(); // as side effect, files may be added to zipOut
221 if (zip) {
222 ZipEntry entry = new ZipEntry("session.jos");
223 zipOut.putNextEntry(entry);
224 writeJos(doc, zipOut);
225 zipOut.close();
226 } else {
227 writeJos(doc, new BufferedOutputStream(out));
228 }
229 Utils.close(out);
230 }
231}
Note: See TracBrowser for help on using the repository browser.