source: josm/trunk/src/org/openstreetmap/josm/io/session/SessionReader.java@ 14630

Last change on this file since 14630 was 14201, checked in by Don-vip, 6 years ago

spotbugs - fix various issues found with Eclipse plugin

  • Property svn:eol-style set to native
File size: 29.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.session;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GraphicsEnvironment;
7import java.io.BufferedInputStream;
8import java.io.File;
9import java.io.FileNotFoundException;
10import java.io.IOException;
11import java.io.InputStream;
12import java.lang.reflect.InvocationTargetException;
13import java.net.URI;
14import java.net.URISyntaxException;
15import java.nio.charset.StandardCharsets;
16import java.nio.file.Files;
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.Enumeration;
21import java.util.HashMap;
22import java.util.List;
23import java.util.Map;
24import java.util.Map.Entry;
25import java.util.TreeMap;
26import java.util.zip.ZipEntry;
27import java.util.zip.ZipException;
28import java.util.zip.ZipFile;
29
30import javax.swing.JOptionPane;
31import javax.swing.SwingUtilities;
32import javax.xml.parsers.ParserConfigurationException;
33
34import org.openstreetmap.josm.data.ViewportData;
35import org.openstreetmap.josm.data.coor.EastNorth;
36import org.openstreetmap.josm.data.coor.LatLon;
37import org.openstreetmap.josm.data.projection.Projection;
38import org.openstreetmap.josm.gui.ExtendedDialog;
39import org.openstreetmap.josm.gui.MainApplication;
40import org.openstreetmap.josm.gui.layer.Layer;
41import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
42import org.openstreetmap.josm.gui.progress.ProgressMonitor;
43import org.openstreetmap.josm.io.Compression;
44import org.openstreetmap.josm.io.IllegalDataException;
45import org.openstreetmap.josm.tools.CheckParameterUtil;
46import org.openstreetmap.josm.tools.JosmRuntimeException;
47import org.openstreetmap.josm.tools.Logging;
48import org.openstreetmap.josm.tools.MultiMap;
49import org.openstreetmap.josm.tools.Utils;
50import org.openstreetmap.josm.tools.XmlUtils;
51import org.w3c.dom.Document;
52import org.w3c.dom.Element;
53import org.w3c.dom.Node;
54import org.w3c.dom.NodeList;
55import org.xml.sax.SAXException;
56
57/**
58 * Reads a .jos session file and loads the layers in the process.
59 * @since 4668
60 */
61public class SessionReader {
62
63 /**
64 * Data class for projection saved in the session file.
65 */
66 public static class SessionProjectionChoiceData {
67 private final String projectionChoiceId;
68 private final Collection<String> subPreferences;
69
70 /**
71 * Construct a new SessionProjectionChoiceData.
72 * @param projectionChoiceId projection choice id
73 * @param subPreferences parameters for the projection choice
74 */
75 public SessionProjectionChoiceData(String projectionChoiceId, Collection<String> subPreferences) {
76 this.projectionChoiceId = projectionChoiceId;
77 this.subPreferences = subPreferences;
78 }
79
80 /**
81 * Get the projection choice id.
82 * @return the projection choice id
83 */
84 public String getProjectionChoiceId() {
85 return projectionChoiceId;
86 }
87
88 /**
89 * Get the parameters for the projection choice
90 * @return parameters for the projection choice
91 */
92 public Collection<String> getSubPreferences() {
93 return subPreferences;
94 }
95 }
96
97 /**
98 * Data class for viewport saved in the session file.
99 */
100 public static class SessionViewportData {
101 private final LatLon center;
102 private final double meterPerPixel;
103
104 /**
105 * Construct a new SessionViewportData.
106 * @param center the lat/lon coordinates of the screen center
107 * @param meterPerPixel scale in meters per pixel
108 */
109 public SessionViewportData(LatLon center, double meterPerPixel) {
110 CheckParameterUtil.ensureParameterNotNull(center);
111 this.center = center;
112 this.meterPerPixel = meterPerPixel;
113 }
114
115 /**
116 * Get the lat/lon coordinates of the screen center.
117 * @return lat/lon coordinates of the screen center
118 */
119 public LatLon getCenter() {
120 return center;
121 }
122
123 /**
124 * Get the scale in meters per pixel.
125 * @return scale in meters per pixel
126 */
127 public double getScale() {
128 return meterPerPixel;
129 }
130
131 /**
132 * Convert this viewport data to a {@link ViewportData} object (with projected coordinates).
133 * @param proj the projection to convert from lat/lon to east/north
134 * @return the corresponding ViewportData object
135 */
136 public ViewportData getEastNorthViewport(Projection proj) {
137 EastNorth centerEN = proj.latlon2eastNorth(center);
138 // Get a "typical" distance in east/north units that
139 // corresponds to a couple of pixels. Shouldn't be too
140 // large, to keep it within projection bounds and
141 // not too small to avoid rounding errors.
142 double dist = 0.01 * proj.getDefaultZoomInPPD();
143 LatLon ll1 = proj.eastNorth2latlon(new EastNorth(centerEN.east() - dist, centerEN.north()));
144 LatLon ll2 = proj.eastNorth2latlon(new EastNorth(centerEN.east() + dist, centerEN.north()));
145 double meterPerEasting = ll1.greatCircleDistance(ll2) / dist / 2;
146 double scale = meterPerPixel / meterPerEasting; // unit: easting per pixel
147 return new ViewportData(centerEN, scale);
148 }
149 }
150
151 private static final Map<String, Class<? extends SessionLayerImporter>> sessionLayerImporters = new HashMap<>();
152
153 private URI sessionFileURI;
154 private boolean zip; // true, if session file is a .joz file; false if it is a .jos file
155 private ZipFile zipFile;
156 private List<Layer> layers = new ArrayList<>();
157 private int active = -1;
158 private final List<Runnable> postLoadTasks = new ArrayList<>();
159 private SessionViewportData viewport;
160 private SessionProjectionChoiceData projectionChoice;
161
162 static {
163 registerSessionLayerImporter("osm-data", OsmDataSessionImporter.class);
164 registerSessionLayerImporter("imagery", ImagerySessionImporter.class);
165 registerSessionLayerImporter("tracks", GpxTracksSessionImporter.class);
166 registerSessionLayerImporter("geoimage", GeoImageSessionImporter.class);
167 registerSessionLayerImporter("markers", MarkerSessionImporter.class);
168 registerSessionLayerImporter("osm-notes", NoteSessionImporter.class);
169 }
170
171 /**
172 * Register a session layer importer.
173 *
174 * @param layerType layer type
175 * @param importer importer for this layer class
176 */
177 public static void registerSessionLayerImporter(String layerType, Class<? extends SessionLayerImporter> importer) {
178 sessionLayerImporters.put(layerType, importer);
179 }
180
181 /**
182 * Returns the session layer importer for the given layer type.
183 * @param layerType layer type to import
184 * @return session layer importer for the given layer
185 */
186 public static SessionLayerImporter getSessionLayerImporter(String layerType) {
187 Class<? extends SessionLayerImporter> importerClass = sessionLayerImporters.get(layerType);
188 if (importerClass == null)
189 return null;
190 SessionLayerImporter importer = null;
191 try {
192 importer = importerClass.getConstructor().newInstance();
193 } catch (ReflectiveOperationException e) {
194 throw new JosmRuntimeException(e);
195 }
196 return importer;
197 }
198
199 /**
200 * @return list of layers that are later added to the mapview
201 */
202 public List<Layer> getLayers() {
203 return layers;
204 }
205
206 /**
207 * @return active layer, or {@code null} if not set
208 * @since 6271
209 */
210 public Layer getActive() {
211 // layers is in reverse order because of the way TreeMap is built
212 return (active >= 0 && active < layers.size()) ? layers.get(layers.size()-1-active) : null;
213 }
214
215 /**
216 * @return actions executed in EDT after layers have been added (message dialog, etc.)
217 */
218 public List<Runnable> getPostLoadTasks() {
219 return postLoadTasks;
220 }
221
222 /**
223 * Return the viewport (map position and scale).
224 * @return the viewport; can be null when no viewport info is found in the file
225 */
226 public SessionViewportData getViewport() {
227 return viewport;
228 }
229
230 /**
231 * Return the projection choice data.
232 * @return the projection; can be null when no projection info is found in the file
233 */
234 public SessionProjectionChoiceData getProjectionChoice() {
235 return projectionChoice;
236 }
237
238 /**
239 * A class that provides some context for the individual {@link SessionLayerImporter}
240 * when doing the import.
241 */
242 public class ImportSupport {
243
244 private final String layerName;
245 private final int layerIndex;
246 private final List<LayerDependency> layerDependencies;
247
248 /**
249 * Path of the file inside the zip archive.
250 * Used as alternative return value for getFile method.
251 */
252 private String inZipPath;
253
254 /**
255 * Constructs a new {@code ImportSupport}.
256 * @param layerName layer name
257 * @param layerIndex layer index
258 * @param layerDependencies layer dependencies
259 */
260 public ImportSupport(String layerName, int layerIndex, List<LayerDependency> layerDependencies) {
261 this.layerName = layerName;
262 this.layerIndex = layerIndex;
263 this.layerDependencies = layerDependencies;
264 }
265
266 /**
267 * Add a task, e.g. a message dialog, that should
268 * be executed in EDT after all layers have been added.
269 * @param task task to run in EDT
270 */
271 public void addPostLayersTask(Runnable task) {
272 postLoadTasks.add(task);
273 }
274
275 /**
276 * Return an InputStream for a URI from a .jos/.joz file.
277 *
278 * The following forms are supported:
279 *
280 * - absolute file (both .jos and .joz):
281 * "file:///home/user/data.osm"
282 * "file:/home/user/data.osm"
283 * "file:///C:/files/data.osm"
284 * "file:/C:/file/data.osm"
285 * "/home/user/data.osm"
286 * "C:\files\data.osm" (not a URI, but recognized by File constructor on Windows systems)
287 * - standalone .jos files:
288 * - relative uri:
289 * "save/data.osm"
290 * "../project2/data.osm"
291 * - for .joz files:
292 * - file inside zip archive:
293 * "layers/01/data.osm"
294 * - relativ to the .joz file:
295 * "../save/data.osm" ("../" steps out of the archive)
296 * @param uriStr URI as string
297 * @return the InputStream
298 *
299 * @throws IOException Thrown when no Stream can be opened for the given URI, e.g. when the linked file has been deleted.
300 */
301 public InputStream getInputStream(String uriStr) throws IOException {
302 File file = getFile(uriStr);
303 if (file != null) {
304 try {
305 return new BufferedInputStream(Compression.getUncompressedFileInputStream(file));
306 } catch (FileNotFoundException e) {
307 throw new IOException(tr("File ''{0}'' does not exist.", file.getPath()), e);
308 }
309 } else if (inZipPath != null) {
310 ZipEntry entry = zipFile.getEntry(inZipPath);
311 if (entry != null) {
312 return zipFile.getInputStream(entry);
313 }
314 }
315 throw new IOException(tr("Unable to locate file ''{0}''.", uriStr));
316 }
317
318 /**
319 * Return a File for a URI from a .jos/.joz file.
320 *
321 * Returns null if the URI points to a file inside the zip archive.
322 * In this case, inZipPath will be set to the corresponding path.
323 * @param uriStr the URI as string
324 * @return the resulting File
325 * @throws IOException if any I/O error occurs
326 */
327 public File getFile(String uriStr) throws IOException {
328 inZipPath = null;
329 try {
330 URI uri = new URI(uriStr);
331 if ("file".equals(uri.getScheme()))
332 // absolute path
333 return new File(uri);
334 else if (uri.getScheme() == null) {
335 // Check if this is an absolute path without 'file:' scheme part.
336 // At this point, (as an exception) platform dependent path separator will be recognized.
337 // (This form is discouraged, only for users that like to copy and paste a path manually.)
338 File file = new File(uriStr);
339 if (file.isAbsolute())
340 return file;
341 else {
342 // for relative paths, only forward slashes are permitted
343 if (isZip()) {
344 if (uri.getPath().startsWith("../")) {
345 // relative to session file - "../" step out of the archive
346 String relPath = uri.getPath().substring(3);
347 return new File(sessionFileURI.resolve(relPath));
348 } else {
349 // file inside zip archive
350 inZipPath = uriStr;
351 return null;
352 }
353 } else
354 return new File(sessionFileURI.resolve(uri));
355 }
356 } else
357 throw new IOException(tr("Unsupported scheme ''{0}'' in URI ''{1}''.", uri.getScheme(), uriStr));
358 } catch (URISyntaxException | IllegalArgumentException e) {
359 throw new IOException(e);
360 }
361 }
362
363 /**
364 * Determines if we are reading from a .joz file.
365 * @return {@code true} if we are reading from a .joz file, {@code false} otherwise
366 */
367 public boolean isZip() {
368 return zip;
369 }
370
371 /**
372 * Name of the layer that is currently imported.
373 * @return layer name
374 */
375 public String getLayerName() {
376 return layerName;
377 }
378
379 /**
380 * Index of the layer that is currently imported.
381 * @return layer index
382 */
383 public int getLayerIndex() {
384 return layerIndex;
385 }
386
387 /**
388 * Dependencies - maps the layer index to the importer of the given
389 * layer. All the dependent importers have loaded completely at this point.
390 * @return layer dependencies
391 */
392 public List<LayerDependency> getLayerDependencies() {
393 return layerDependencies;
394 }
395
396 @Override
397 public String toString() {
398 return "ImportSupport [layerName=" + layerName + ", layerIndex=" + layerIndex + ", layerDependencies="
399 + layerDependencies + ", inZipPath=" + inZipPath + ']';
400 }
401 }
402
403 public static class LayerDependency {
404 private final Integer index;
405 private final Layer layer;
406 private final SessionLayerImporter importer;
407
408 public LayerDependency(Integer index, Layer layer, SessionLayerImporter importer) {
409 this.index = index;
410 this.layer = layer;
411 this.importer = importer;
412 }
413
414 public SessionLayerImporter getImporter() {
415 return importer;
416 }
417
418 public Integer getIndex() {
419 return index;
420 }
421
422 public Layer getLayer() {
423 return layer;
424 }
425 }
426
427 private static void error(String msg) throws IllegalDataException {
428 throw new IllegalDataException(msg);
429 }
430
431 private void parseJos(Document doc, ProgressMonitor progressMonitor) throws IllegalDataException {
432 Element root = doc.getDocumentElement();
433 if (!"josm-session".equals(root.getTagName())) {
434 error(tr("Unexpected root element ''{0}'' in session file", root.getTagName()));
435 }
436 String version = root.getAttribute("version");
437 if (!"0.1".equals(version)) {
438 error(tr("Version ''{0}'' of session file is not supported. Expected: 0.1", version));
439 }
440
441 viewport = readViewportData(root);
442 projectionChoice = readProjectionChoiceData(root);
443
444 Element layersEl = getElementByTagName(root, "layers");
445 if (layersEl == null) return;
446
447 String activeAtt = layersEl.getAttribute("active");
448 try {
449 active = !activeAtt.isEmpty() ? (Integer.parseInt(activeAtt)-1) : -1;
450 } catch (NumberFormatException e) {
451 Logging.warn("Unsupported value for 'active' layer attribute. Ignoring it. Error was: "+e.getMessage());
452 active = -1;
453 }
454
455 MultiMap<Integer, Integer> deps = new MultiMap<>();
456 Map<Integer, Element> elems = new HashMap<>();
457
458 NodeList nodes = layersEl.getChildNodes();
459
460 for (int i = 0; i < nodes.getLength(); ++i) {
461 Node node = nodes.item(i);
462 if (node.getNodeType() == Node.ELEMENT_NODE) {
463 Element e = (Element) node;
464 if ("layer".equals(e.getTagName())) {
465 if (!e.hasAttribute("index")) {
466 error(tr("missing mandatory attribute ''index'' for element ''layer''"));
467 }
468 Integer idx = null;
469 try {
470 idx = Integer.valueOf(e.getAttribute("index"));
471 } catch (NumberFormatException ex) {
472 Logging.warn(ex);
473 }
474 if (idx == null) {
475 error(tr("unexpected format of attribute ''index'' for element ''layer''"));
476 } else if (elems.containsKey(idx)) {
477 error(tr("attribute ''index'' ({0}) for element ''layer'' must be unique", Integer.toString(idx)));
478 }
479 elems.put(idx, e);
480
481 deps.putVoid(idx);
482 String depStr = e.getAttribute("depends");
483 if (!depStr.isEmpty()) {
484 for (String sd : depStr.split(",")) {
485 Integer d = null;
486 try {
487 d = Integer.valueOf(sd);
488 } catch (NumberFormatException ex) {
489 Logging.warn(ex);
490 }
491 if (d != null) {
492 deps.put(idx, d);
493 }
494 }
495 }
496 }
497 }
498 }
499
500 List<Integer> sorted = Utils.topologicalSort(deps);
501 final Map<Integer, Layer> layersMap = new TreeMap<>(Collections.reverseOrder());
502 final Map<Integer, SessionLayerImporter> importers = new HashMap<>();
503 final Map<Integer, String> names = new HashMap<>();
504
505 progressMonitor.setTicksCount(sorted.size());
506 LAYER: for (int idx: sorted) {
507 Element e = elems.get(idx);
508 if (e == null) {
509 error(tr("missing layer with index {0}", idx));
510 return;
511 } else if (!e.hasAttribute("name")) {
512 error(tr("missing mandatory attribute ''name'' for element ''layer''"));
513 return;
514 }
515 String name = e.getAttribute("name");
516 names.put(idx, name);
517 if (!e.hasAttribute("type")) {
518 error(tr("missing mandatory attribute ''type'' for element ''layer''"));
519 return;
520 }
521 String type = e.getAttribute("type");
522 SessionLayerImporter imp = getSessionLayerImporter(type);
523 if (imp == null && !GraphicsEnvironment.isHeadless()) {
524 CancelOrContinueDialog dialog = new CancelOrContinueDialog();
525 dialog.show(
526 tr("Unable to load layer"),
527 tr("Cannot load layer of type ''{0}'' because no suitable importer was found.", type),
528 JOptionPane.WARNING_MESSAGE,
529 progressMonitor
530 );
531 if (dialog.isCancel()) {
532 progressMonitor.cancel();
533 return;
534 } else {
535 continue;
536 }
537 } else if (imp != null) {
538 importers.put(idx, imp);
539 List<LayerDependency> depsImp = new ArrayList<>();
540 for (int d : deps.get(idx)) {
541 SessionLayerImporter dImp = importers.get(d);
542 if (dImp == null) {
543 CancelOrContinueDialog dialog = new CancelOrContinueDialog();
544 dialog.show(
545 tr("Unable to load layer"),
546 tr("Cannot load layer {0} because it depends on layer {1} which has been skipped.", idx, d),
547 JOptionPane.WARNING_MESSAGE,
548 progressMonitor
549 );
550 if (dialog.isCancel()) {
551 progressMonitor.cancel();
552 return;
553 } else {
554 continue LAYER;
555 }
556 }
557 depsImp.add(new LayerDependency(d, layersMap.get(d), dImp));
558 }
559 ImportSupport support = new ImportSupport(name, idx, depsImp);
560 Layer layer = null;
561 Exception exception = null;
562 try {
563 layer = imp.load(e, support, progressMonitor.createSubTaskMonitor(1, false));
564 if (layer == null) {
565 throw new IllegalStateException("Importer " + imp + " returned null for " + support);
566 }
567 } catch (IllegalDataException | IllegalStateException | IOException ex) {
568 exception = ex;
569 }
570 if (exception != null) {
571 Logging.error(exception);
572 if (!GraphicsEnvironment.isHeadless()) {
573 CancelOrContinueDialog dialog = new CancelOrContinueDialog();
574 dialog.show(
575 tr("Error loading layer"),
576 tr("<html>Could not load layer {0} ''{1}''.<br>Error is:<br>{2}</html>", idx,
577 Utils.escapeReservedCharactersHTML(name),
578 Utils.escapeReservedCharactersHTML(exception.getMessage())),
579 JOptionPane.ERROR_MESSAGE,
580 progressMonitor
581 );
582 if (dialog.isCancel()) {
583 progressMonitor.cancel();
584 return;
585 } else {
586 continue;
587 }
588 }
589 }
590
591 layersMap.put(idx, layer);
592 }
593 progressMonitor.worked(1);
594 }
595
596 layers = new ArrayList<>();
597 for (Entry<Integer, Layer> entry : layersMap.entrySet()) {
598 Layer layer = entry.getValue();
599 if (layer == null) {
600 continue;
601 }
602 Element el = elems.get(entry.getKey());
603 if (el.hasAttribute("visible")) {
604 layer.setVisible(Boolean.parseBoolean(el.getAttribute("visible")));
605 }
606 if (el.hasAttribute("opacity")) {
607 try {
608 double opacity = Double.parseDouble(el.getAttribute("opacity"));
609 layer.setOpacity(opacity);
610 } catch (NumberFormatException ex) {
611 Logging.warn(ex);
612 }
613 }
614 layer.setName(names.get(entry.getKey()));
615 layers.add(layer);
616 }
617 }
618
619 private static SessionViewportData readViewportData(Element root) {
620 Element viewportEl = getElementByTagName(root, "viewport");
621 if (viewportEl == null) return null;
622 LatLon center = null;
623 Element centerEl = getElementByTagName(viewportEl, "center");
624 if (centerEl == null || !centerEl.hasAttribute("lat") || !centerEl.hasAttribute("lon")) return null;
625 try {
626 center = new LatLon(Double.parseDouble(centerEl.getAttribute("lat")),
627 Double.parseDouble(centerEl.getAttribute("lon")));
628 } catch (NumberFormatException ex) {
629 Logging.warn(ex);
630 }
631 if (center == null) return null;
632 Element scaleEl = getElementByTagName(viewportEl, "scale");
633 if (scaleEl == null || !scaleEl.hasAttribute("meter-per-pixel")) return null;
634 try {
635 double scale = Double.parseDouble(scaleEl.getAttribute("meter-per-pixel"));
636 return new SessionViewportData(center, scale);
637 } catch (NumberFormatException ex) {
638 Logging.warn(ex);
639 return null;
640 }
641 }
642
643 private static SessionProjectionChoiceData readProjectionChoiceData(Element root) {
644 Element projectionEl = getElementByTagName(root, "projection");
645 if (projectionEl == null) return null;
646 Element projectionChoiceEl = getElementByTagName(projectionEl, "projection-choice");
647 if (projectionChoiceEl == null) return null;
648 Element idEl = getElementByTagName(projectionChoiceEl, "id");
649 if (idEl == null) return null;
650 String id = idEl.getTextContent();
651 Element parametersEl = getElementByTagName(projectionChoiceEl, "parameters");
652 if (parametersEl == null) return null;
653 Collection<String> parameters = new ArrayList<>();
654 NodeList paramNl = parametersEl.getElementsByTagName("param");
655 int length = paramNl.getLength();
656 for (int i = 0; i < length; i++) {
657 Element paramEl = (Element) paramNl.item(i);
658 parameters.add(paramEl.getTextContent());
659 }
660 return new SessionProjectionChoiceData(id, parameters);
661 }
662
663 /**
664 * Show Dialog when there is an error for one layer.
665 * Ask the user whether to cancel the complete session loading or just to skip this layer.
666 *
667 * This is expected to run in a worker thread (PleaseWaitRunnable), so invokeAndWait is
668 * needed to block the current thread and wait for the result of the modal dialog from EDT.
669 */
670 private static class CancelOrContinueDialog {
671
672 private boolean cancel;
673
674 public void show(final String title, final String message, final int icon, final ProgressMonitor progressMonitor) {
675 try {
676 SwingUtilities.invokeAndWait(() -> {
677 ExtendedDialog dlg = new ExtendedDialog(
678 MainApplication.getMainFrame(),
679 title,
680 tr("Cancel"), tr("Skip layer and continue"))
681 .setButtonIcons("cancel", "dialogs/next")
682 .setIcon(icon)
683 .setContent(message);
684 cancel = dlg.showDialog().getValue() != 2;
685 });
686 } catch (InvocationTargetException | InterruptedException ex) {
687 throw new JosmRuntimeException(ex);
688 }
689 }
690
691 public boolean isCancel() {
692 return cancel;
693 }
694 }
695
696 /**
697 * Loads session from the given file.
698 * @param sessionFile session file to load
699 * @param zip {@code true} if it's a zipped session (.joz)
700 * @param progressMonitor progress monitor
701 * @throws IllegalDataException if invalid data is detected
702 * @throws IOException if any I/O error occurs
703 */
704 public void loadSession(File sessionFile, boolean zip, ProgressMonitor progressMonitor) throws IllegalDataException, IOException {
705 try (InputStream josIS = createInputStream(sessionFile, zip)) {
706 loadSession(josIS, sessionFile.toURI(), zip, progressMonitor != null ? progressMonitor : NullProgressMonitor.INSTANCE);
707 }
708 }
709
710 private InputStream createInputStream(File sessionFile, boolean zip) throws IOException, IllegalDataException {
711 if (zip) {
712 try {
713 zipFile = new ZipFile(sessionFile, StandardCharsets.UTF_8);
714 return getZipInputStream(zipFile);
715 } catch (ZipException ex) {
716 throw new IOException(ex);
717 }
718 } else {
719 return Files.newInputStream(sessionFile.toPath());
720 }
721 }
722
723 private static InputStream getZipInputStream(ZipFile zipFile) throws IOException, IllegalDataException {
724 ZipEntry josEntry = null;
725 Enumeration<? extends ZipEntry> entries = zipFile.entries();
726 while (entries.hasMoreElements()) {
727 ZipEntry entry = entries.nextElement();
728 if (Utils.hasExtension(entry.getName(), "jos")) {
729 josEntry = entry;
730 break;
731 }
732 }
733 if (josEntry == null) {
734 error(tr("expected .jos file inside .joz archive"));
735 }
736 return zipFile.getInputStream(josEntry);
737 }
738
739 private void loadSession(InputStream josIS, URI sessionFileURI, boolean zip, ProgressMonitor progressMonitor)
740 throws IOException, IllegalDataException {
741
742 this.sessionFileURI = sessionFileURI;
743 this.zip = zip;
744
745 try {
746 parseJos(XmlUtils.parseSafeDOM(josIS), progressMonitor);
747 } catch (SAXException e) {
748 throw new IllegalDataException(e);
749 } catch (ParserConfigurationException e) {
750 throw new IOException(e);
751 }
752 }
753
754 private static Element getElementByTagName(Element root, String name) {
755 NodeList els = root.getElementsByTagName(name);
756 return els.getLength() > 0 ? (Element) els.item(0) : null;
757 }
758}
Note: See TracBrowser for help on using the repository browser.