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

Last change on this file since 12488 was 12488, checked in by Don-vip, 7 years ago

see #14877 - checkstyle

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