From c57adb7199850a5f7b45cf1711b621b3dc7e6d14 Mon Sep 17 00:00:00 2001 From: gbburkhardt Date: Wed, 25 Oct 2017 21:21:42 -0400 Subject: [PATCH 1/5] correct test for DTED extension; files can use either upper or lower case for file extension --- .../examples/dataimport/InstallDTED.java | 540 +++++++++--------- 1 file changed, 270 insertions(+), 270 deletions(-) diff --git a/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java b/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java index a7035ec041..5c5d804a52 100644 --- a/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java +++ b/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java @@ -1,270 +1,270 @@ -/* - * Copyright (C) 2015 United States Government as represented by the Administrator of the - * National Aeronautics and Space Administration. - * All Rights Reserved. - */ - -package gov.nasa.worldwindx.examples.dataimport; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.avlist.*; -import gov.nasa.worldwind.cache.FileStore; -import gov.nasa.worldwind.data.TiledElevationProducer; -import gov.nasa.worldwind.geom.Sector; -import gov.nasa.worldwind.globes.ElevationModel; -import gov.nasa.worldwind.terrain.CompoundElevationModel; -import gov.nasa.worldwind.util.WWIO; -import gov.nasa.worldwindx.examples.ApplicationTemplate; -import gov.nasa.worldwindx.examples.util.ExampleUtil; -import org.w3c.dom.Document; - -import javax.swing.*; -import javax.swing.Timer; -import java.awt.*; -import java.awt.event.*; -import java.beans.*; -import java.io.File; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Shows how to install a collection of DTED data. - * - * @author tag - * @version $Id: InstallDTED.java 2915 2015-03-20 16:48:43Z tgaskins $ - */ -public class InstallDTED extends ApplicationTemplate -{ - // Define a subdirectory in the installed-data area to place the installed elevation tiles. - protected static final String BASE_CACHE_PATH = "DTED0/"; - - // Override ApplicationTemplate.AppFrame's constructor to install an elevation dataset. - public static class AppFrame extends ApplicationTemplate.AppFrame - { - protected ProgressMonitor progressMonitor; - protected PropertyChangeListener progressListener; - protected java.util.Timer progressTimer; - protected TiledElevationProducer producer; - - public AppFrame() - { - Timer timer = new Timer(3000, new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle("Choose a DTED folder"); - fileChooser.setApproveButtonText("Choose"); - fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - fileChooser.setMultiSelectionEnabled(false); - int status = fileChooser.showOpenDialog(wwjPanel); - if (status == JFileChooser.APPROVE_OPTION) - { - final File sourceDir = fileChooser.getSelectedFile(); - - // Show the WAIT cursor because the installation may take a while. - setCursor(new Cursor(Cursor.WAIT_CURSOR)); - - // Install the elevations on a thread other than the event-dispatch thread to avoid freezing the UI. - Thread t = new Thread(new Runnable() - { - public void run() - { - installElevations(sourceDir); - - // Clean up everything on the event dispatch thread. - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - // Restore the cursor. - setCursor(Cursor.getDefaultCursor()); - - // Clean up the producer. - producer.removePropertyChangeListener(progressListener); - producer.removeAllDataSources(); - producer = null; - - // Shut down progress monitoring. - progressMonitor.close(); - progressMonitor = null; - progressTimer.cancel(); - progressTimer = null; - } - }); - } - }); - - t.start(); - } - } - }); - timer.setRepeats(false); - timer.start(); - } - - protected void installElevations(File sourceDir) - { - // Get a reference to the FileStore into which we'll install the elevations. - FileStore fileStore = WorldWind.getDataFileStore(); - - // Install the elevations and get the resulting elevation model. - ArrayList sources = new ArrayList(); - this.findDTEDFiles(sourceDir, sources); - System.out.println("Found " + sources.size() + " DTED files."); - final ElevationModel em = installElevations("DTED Elevations", sources, fileStore); - if (em == null) - return; - - // Add the new elevation model to the current (default) one. Must do it on the event dispatch thread. - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - CompoundElevationModel model - = (CompoundElevationModel) AppFrame.this.getWwd().getModel().getGlobe().getElevationModel(); - model.addElevationModel(em); - - // Set the view to look at the installed elevations. Get the location from the elevation model's - // construction parameters. - AVList params = (AVList) em.getValue(AVKey.CONSTRUCTION_PARAMETERS); - Sector sector = (Sector) params.getValue(AVKey.SECTOR); - ExampleUtil.goTo(getWwd(), sector); - } - }); - } - - protected void findDTEDFiles(File directory, ArrayList files) - { - File[] thisDirectoryFiles = directory.listFiles(); - if (thisDirectoryFiles == null) - return; - - for (File file : thisDirectoryFiles) - { - if (file.isDirectory()) - { - this.findDTEDFiles(file, files); - } - else if (file.getName().endsWith("dt0") - || file.getName().endsWith("dt1") - || file.getName().endsWith("dt2")) - { - files.add(file); - } - } - } - - protected ElevationModel installElevations(String displayName, ArrayList sources, FileStore fileStore) - { - // Use the FileStore's install location as the destination for the imported elevation tiles. The install - // location is an area in the data file store for permanent storage. - File fileStoreLocation = DataInstallUtil.getDefaultInstallLocation(fileStore); - - // Create a unique cache name that specifies the FileStore path to the installed elevations. - String cacheName = BASE_CACHE_PATH + WWIO.replaceIllegalFileNameCharacters(displayName); - - // Create a parameter list specifying the install location information. - AVList params = new AVListImpl(); - params.setValue(AVKey.FILE_STORE_LOCATION, fileStoreLocation.getAbsolutePath()); - params.setValue(AVKey.DATA_CACHE_NAME, cacheName); - params.setValue(AVKey.DATASET_NAME, displayName); - - // Instruct the raster producer to produce only three initial levels and to create the remaining - // tiles at whatever level is needed on the fly when the elevations are subsequently used. - params.setValue(AVKey.TILED_RASTER_PRODUCER_LIMIT_MAX_LEVEL, 2); // three initial levels - params.setValue(AVKey.SERVICE_NAME, AVKey.SERVICE_NAME_LOCAL_RASTER_SERVER); // on-the-fly tile creation - - // Create a TiledImageProducer to install the imagery. - this.producer = new TiledElevationProducer(); - this.producer.setStoreParameters(params); - this.producer.offerAllDataSources(sources); - - try - { - // Install the elevations. - System.out.println("Starting production"); - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - setupProgressMonitor(); - } - }); - this.producer.startProduction(); - } - catch (Exception e) - { - this.producer.removeProductionState(); - e.printStackTrace(); - return null; - } - System.out.println("Ending production"); - - // Extract the data configuration document from the production results. If production successfully - // completed, the TiledElevationProducer should always contain a document in the production results, but - // test the results anyway. - Iterable results = this.producer.getProductionResults(); - if (results == null || results.iterator() == null || !results.iterator().hasNext()) - return null; - - Object o = results.iterator().next(); - if (o == null || !(o instanceof Document)) - return null; - - // Construct an ElevationModel by passing the data configuration document to an ElevationModelFactory. - return (ElevationModel) BasicFactory.create(AVKey.ELEVATION_MODEL_FACTORY, - ((Document) o).getDocumentElement()); - } - - protected void setupProgressMonitor() - { - // Create a ProgressMonitor that will provide feedback on the installation. - this.progressMonitor = new ProgressMonitor(this.wwjPanel, "Installing", null, 0, 100); - - final AtomicInteger progress = new AtomicInteger(0); - - // Configure the ProgressMonitor to receive progress events from the DataStoreProducer. This stops sending - // progress events when the user clicks the "Cancel" button, ensuring that the ProgressMonitor does not - this.progressListener = new PropertyChangeListener() - { - public void propertyChange(PropertyChangeEvent evt) - { - if (progressMonitor.isCanceled()) - return; - - if (evt.getPropertyName().equals(AVKey.PROGRESS)) - progress.set((int) (100 * (Double) evt.getNewValue())); - } - }; - this.producer.addPropertyChangeListener(this.progressListener); - this.progressMonitor.setProgress(0); - - // Configure a timer to check if the user has clicked the ProgressMonitor's "Cancel" button. If so, stop - // production as soon as possible. This just stops the production from completing; it doesn't clean up any state - // changes made during production, - this.progressTimer = new java.util.Timer(); - this.progressTimer.schedule(new TimerTask() - { - public void run() - { - progressMonitor.setProgress(progress.get()); - - if (progressMonitor.isCanceled()) - { - producer.stopProduction(); - this.cancel(); - } - } - }, progressMonitor.getMillisToDecideToPopup(), 100L); - } - } - - public static void main(String[] args) - { - ApplicationTemplate.start("WorldWind DTED Installation", InstallDTED.AppFrame.class); - } -} +/* + * Copyright (C) 2015 United States Government as represented by the Administrator of the + * National Aeronautics and Space Administration. + * All Rights Reserved. + */ + +package gov.nasa.worldwindx.examples.dataimport; + +import gov.nasa.worldwind.*; +import gov.nasa.worldwind.avlist.*; +import gov.nasa.worldwind.cache.FileStore; +import gov.nasa.worldwind.data.TiledElevationProducer; +import gov.nasa.worldwind.geom.Sector; +import gov.nasa.worldwind.globes.ElevationModel; +import gov.nasa.worldwind.terrain.CompoundElevationModel; +import gov.nasa.worldwind.util.WWIO; +import gov.nasa.worldwindx.examples.ApplicationTemplate; +import gov.nasa.worldwindx.examples.util.ExampleUtil; +import org.w3c.dom.Document; + +import javax.swing.*; +import javax.swing.Timer; +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import java.io.File; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Shows how to install a collection of DTED data. + * + * @author tag + * @version $Id: InstallDTED.java 2915 2015-03-20 16:48:43Z tgaskins $ + */ +public class InstallDTED extends ApplicationTemplate +{ + // Define a subdirectory in the installed-data area to place the installed elevation tiles. + protected static final String BASE_CACHE_PATH = "DTED0/"; + + // Override ApplicationTemplate.AppFrame's constructor to install an elevation dataset. + public static class AppFrame extends ApplicationTemplate.AppFrame + { + protected ProgressMonitor progressMonitor; + protected PropertyChangeListener progressListener; + protected java.util.Timer progressTimer; + protected TiledElevationProducer producer; + + public AppFrame() + { + Timer timer = new Timer(3000, new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle("Choose a DTED folder"); + fileChooser.setApproveButtonText("Choose"); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fileChooser.setMultiSelectionEnabled(false); + int status = fileChooser.showOpenDialog(wwjPanel); + if (status == JFileChooser.APPROVE_OPTION) + { + final File sourceDir = fileChooser.getSelectedFile(); + + // Show the WAIT cursor because the installation may take a while. + setCursor(new Cursor(Cursor.WAIT_CURSOR)); + + // Install the elevations on a thread other than the event-dispatch thread to avoid freezing the UI. + Thread t = new Thread(new Runnable() + { + public void run() + { + installElevations(sourceDir); + + // Clean up everything on the event dispatch thread. + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + // Restore the cursor. + setCursor(Cursor.getDefaultCursor()); + + // Clean up the producer. + producer.removePropertyChangeListener(progressListener); + producer.removeAllDataSources(); + producer = null; + + // Shut down progress monitoring. + progressMonitor.close(); + progressMonitor = null; + progressTimer.cancel(); + progressTimer = null; + } + }); + } + }); + + t.start(); + } + } + }); + timer.setRepeats(false); + timer.start(); + } + + protected void installElevations(File sourceDir) + { + // Get a reference to the FileStore into which we'll install the elevations. + FileStore fileStore = WorldWind.getDataFileStore(); + + // Install the elevations and get the resulting elevation model. + ArrayList sources = new ArrayList(); + this.findDTEDFiles(sourceDir, sources); + System.out.println("Found " + sources.size() + " DTED files."); + final ElevationModel em = installElevations("DTED Elevations", sources, fileStore); + if (em == null) + return; + + // Add the new elevation model to the current (default) one. Must do it on the event dispatch thread. + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + CompoundElevationModel model + = (CompoundElevationModel) AppFrame.this.getWwd().getModel().getGlobe().getElevationModel(); + model.addElevationModel(em); + + // Set the view to look at the installed elevations. Get the location from the elevation model's + // construction parameters. + AVList params = (AVList) em.getValue(AVKey.CONSTRUCTION_PARAMETERS); + Sector sector = (Sector) params.getValue(AVKey.SECTOR); + ExampleUtil.goTo(getWwd(), sector); + } + }); + } + + protected void findDTEDFiles(File directory, ArrayList files) + { + File[] thisDirectoryFiles = directory.listFiles(); + if (thisDirectoryFiles == null) + return; + + for (File file : thisDirectoryFiles) + { + if (file.isDirectory()) + { + this.findDTEDFiles(file, files); + } + else if (file.getName().toLowerCase().endsWith("dt0") + || file.getName().toLowerCase().endsWith("dt1") + || file.getName().toLowerCase().endsWith("dt2")) + { + files.add(file); + } + } + } + + protected ElevationModel installElevations(String displayName, ArrayList sources, FileStore fileStore) + { + // Use the FileStore's install location as the destination for the imported elevation tiles. The install + // location is an area in the data file store for permanent storage. + File fileStoreLocation = DataInstallUtil.getDefaultInstallLocation(fileStore); + + // Create a unique cache name that specifies the FileStore path to the installed elevations. + String cacheName = BASE_CACHE_PATH + WWIO.replaceIllegalFileNameCharacters(displayName); + + // Create a parameter list specifying the install location information. + AVList params = new AVListImpl(); + params.setValue(AVKey.FILE_STORE_LOCATION, fileStoreLocation.getAbsolutePath()); + params.setValue(AVKey.DATA_CACHE_NAME, cacheName); + params.setValue(AVKey.DATASET_NAME, displayName); + + // Instruct the raster producer to produce only three initial levels and to create the remaining + // tiles at whatever level is needed on the fly when the elevations are subsequently used. + params.setValue(AVKey.TILED_RASTER_PRODUCER_LIMIT_MAX_LEVEL, 2); // three initial levels + params.setValue(AVKey.SERVICE_NAME, AVKey.SERVICE_NAME_LOCAL_RASTER_SERVER); // on-the-fly tile creation + + // Create a TiledImageProducer to install the imagery. + this.producer = new TiledElevationProducer(); + this.producer.setStoreParameters(params); + this.producer.offerAllDataSources(sources); + + try + { + // Install the elevations. + System.out.println("Starting production"); + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + setupProgressMonitor(); + } + }); + this.producer.startProduction(); + } + catch (Exception e) + { + this.producer.removeProductionState(); + e.printStackTrace(); + return null; + } + System.out.println("Ending production"); + + // Extract the data configuration document from the production results. If production successfully + // completed, the TiledElevationProducer should always contain a document in the production results, but + // test the results anyway. + Iterable results = this.producer.getProductionResults(); + if (results == null || results.iterator() == null || !results.iterator().hasNext()) + return null; + + Object o = results.iterator().next(); + if (o == null || !(o instanceof Document)) + return null; + + // Construct an ElevationModel by passing the data configuration document to an ElevationModelFactory. + return (ElevationModel) BasicFactory.create(AVKey.ELEVATION_MODEL_FACTORY, + ((Document) o).getDocumentElement()); + } + + protected void setupProgressMonitor() + { + // Create a ProgressMonitor that will provide feedback on the installation. + this.progressMonitor = new ProgressMonitor(this.wwjPanel, "Installing", null, 0, 100); + + final AtomicInteger progress = new AtomicInteger(0); + + // Configure the ProgressMonitor to receive progress events from the DataStoreProducer. This stops sending + // progress events when the user clicks the "Cancel" button, ensuring that the ProgressMonitor does not + this.progressListener = new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent evt) + { + if (progressMonitor.isCanceled()) + return; + + if (evt.getPropertyName().equals(AVKey.PROGRESS)) + progress.set((int) (100 * (Double) evt.getNewValue())); + } + }; + this.producer.addPropertyChangeListener(this.progressListener); + this.progressMonitor.setProgress(0); + + // Configure a timer to check if the user has clicked the ProgressMonitor's "Cancel" button. If so, stop + // production as soon as possible. This just stops the production from completing; it doesn't clean up any state + // changes made during production, + this.progressTimer = new java.util.Timer(); + this.progressTimer.schedule(new TimerTask() + { + public void run() + { + progressMonitor.setProgress(progress.get()); + + if (progressMonitor.isCanceled()) + { + producer.stopProduction(); + this.cancel(); + } + } + }, progressMonitor.getMillisToDecideToPopup(), 100L); + } + } + + public static void main(String[] args) + { + ApplicationTemplate.start("WorldWind DTED Installation", InstallDTED.AppFrame.class); + } +} From ecd04b41b66ce0cbbe28506500de49e1dfc6d1e4 Mon Sep 17 00:00:00 2001 From: gbburkhardt Date: Wed, 25 Oct 2017 21:21:42 -0400 Subject: [PATCH 2/5] correct test for DTED extension; files can use either upper or lower case for file extension --- .../nasa/worldwindx/examples/dataimport/InstallDTED.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java b/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java index a7035ec041..13cb4a1be6 100644 --- a/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java +++ b/src/gov/nasa/worldwindx/examples/dataimport/InstallDTED.java @@ -148,9 +148,9 @@ protected void findDTEDFiles(File directory, ArrayList files) { this.findDTEDFiles(file, files); } - else if (file.getName().endsWith("dt0") - || file.getName().endsWith("dt1") - || file.getName().endsWith("dt2")) + else if (file.getName().toLowerCase().endsWith("dt0") + || file.getName().toLowerCase().endsWith("dt1") + || file.getName().toLowerCase().endsWith("dt2")) { files.add(file); } From e709e4ffb9e996b994979126288de84806e07e4d Mon Sep 17 00:00:00 2001 From: Glenn Burkhardt Date: Wed, 7 Feb 2018 17:34:30 -0500 Subject: [PATCH 3/5] avoid memory/resource leaks --- .../worldwind/data/BasicRasterServer.java | 2 ++ .../data/RasterServerConfiguration.java | 10 ++++++ src/gov/nasa/worldwind/util/WWXML.java | 33 ++++++++++++++----- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/gov/nasa/worldwind/data/BasicRasterServer.java b/src/gov/nasa/worldwind/data/BasicRasterServer.java index f632cd6291..53321f77da 100644 --- a/src/gov/nasa/worldwind/data/BasicRasterServer.java +++ b/src/gov/nasa/worldwind/data/BasicRasterServer.java @@ -140,6 +140,8 @@ protected void init(Object o) String message = Logging.getMessage("generic.DataSetLimitedAvailability", this.getDataSetName() ); Logging.logger().severe(message); } + + config.dispose(); } protected String getDataSetName() diff --git a/src/gov/nasa/worldwind/data/RasterServerConfiguration.java b/src/gov/nasa/worldwind/data/RasterServerConfiguration.java index f69e5ec37c..b252da97f7 100644 --- a/src/gov/nasa/worldwind/data/RasterServerConfiguration.java +++ b/src/gov/nasa/worldwind/data/RasterServerConfiguration.java @@ -143,6 +143,16 @@ public RasterServerConfiguration(Object docSource) this.initialize(); } + + public void dispose() { + try { + eventReader.close(); + } catch (XMLStreamException e) { + e.printStackTrace(); + } + WWXML.closeEventReader(eventReader, "RasterServerConfiguration"); + freeResources(); + } protected void initialize() { diff --git a/src/gov/nasa/worldwind/util/WWXML.java b/src/gov/nasa/worldwind/util/WWXML.java index 80827c22a4..fd94eb962b 100644 --- a/src/gov/nasa/worldwind/util/WWXML.java +++ b/src/gov/nasa/worldwind/util/WWXML.java @@ -39,6 +39,8 @@ public class WWXML { public static final String XLINK_URI = "http://www.w3.org/1999/xlink"; + private static Map inputSources = new HashMap(); + /** * Create a DOM builder. * @@ -170,9 +172,12 @@ public static Document openDocumentFile(String filePath, Class c) throw new IllegalArgumentException(message); } - InputStream inputStream = WWIO.openFileOrResourceStream(filePath, c); - - return inputStream != null ? openDocumentStream(inputStream) : null; + try (InputStream inputStream = WWIO.openFileOrResourceStream(filePath, c)) { + return inputStream != null ? openDocumentStream(inputStream) : null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } } /** @@ -273,10 +278,7 @@ public static void saveDocumentToFile(Document doc, String filePath) throw new IllegalArgumentException(message); } - try - { - java.io.FileOutputStream outputStream = new java.io.FileOutputStream(filePath); - + try (java.io.FileOutputStream outputStream = new java.io.FileOutputStream(filePath)) { saveDocumentToStream(doc, outputStream); } catch (IOException e) @@ -356,7 +358,9 @@ public static XMLEventReader openEventReaderStream(InputStream inputStream, bool try { - return inputFactory.createXMLEventReader(inputStream); + XMLEventReader reader = inputFactory.createXMLEventReader(inputStream); + inputSources.put(reader, inputStream); + return reader; } catch (XMLStreamException e) { @@ -440,7 +444,9 @@ public static XMLEventReader openEventReaderURL(URL url, boolean isNamespaceAwar try { InputStream inputStream = url.openStream(); - return openEventReaderStream(inputStream, isNamespaceAware); + XMLEventReader reader = openEventReaderStream(inputStream, isNamespaceAware); + inputSources.put(reader, inputStream); + return reader; } catch (IOException e) { @@ -531,6 +537,15 @@ public static void closeEventReader(XMLEventReader eventReader, String name) try { eventReader.close(); + InputStream is = inputSources.get(eventReader); + if (is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + inputSources.remove(eventReader); + } } catch (XMLStreamException e) { From 45e243d57ade0c5e173817efccc757a2367556c6 Mon Sep 17 00:00:00 2001 From: Glenn Burkhardt Date: Wed, 7 Feb 2018 17:39:09 -0500 Subject: [PATCH 4/5] add handling for error conditions --- .../util/DataConfigurationUtils.java | 14 ++++++++++-- .../worldwind/util/MessageStrings.properties | 1 + .../ElevationModelManagerPanel.java | 1 + .../examples/util/WCSCoveragePanel.java | 22 +++++++++++++++---- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/gov/nasa/worldwind/util/DataConfigurationUtils.java b/src/gov/nasa/worldwind/util/DataConfigurationUtils.java index 10c94f7c10..edf0837a8a 100644 --- a/src/gov/nasa/worldwind/util/DataConfigurationUtils.java +++ b/src/gov/nasa/worldwind/util/DataConfigurationUtils.java @@ -753,8 +753,9 @@ public static AVList getWMSLayerConfigParams(WMSCapabilities caps, String[] form WMSLayerCapabilities layerCaps = caps.getLayerByName(name); if (layerCaps == null) { - Logging.logger().warning(Logging.getMessage("WMS.LayerNameMissing", name)); - continue; + String msg = Logging.getMessage("WMS.LayerNameMissing", name); + Logging.logger().warning(msg); + throw new WWRuntimeException(msg); } if (layerCaps.hasCoordinateSystem("EPSG:4326")) @@ -903,6 +904,13 @@ public static AVList getWCSConfigParameters(WCS100Capabilities caps, WCS100Descr throw new IllegalArgumentException(message); } + if (coverage.getCoverageOfferings().size() == 0) + { + String message = Logging.getMessage("AbsentResourceList.WCSDescribeCoverage"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + if (params == null) { String message = Logging.getMessage("nullValue.ParametersIsNull"); @@ -1135,6 +1143,8 @@ protected static String makeTitle(WMSCapabilities caps, String layerNames, Strin String layerName = lNames[i]; WMSLayerCapabilities layer = caps.getLayerByName(layerName); + if (layer == null) continue; // layer not found + String layerTitle = layer.getTitle(); sb.append(layerTitle != null ? layerTitle : layerName); diff --git a/src/gov/nasa/worldwind/util/MessageStrings.properties b/src/gov/nasa/worldwind/util/MessageStrings.properties index 8a0793dc83..ce08cf30a1 100644 --- a/src/gov/nasa/worldwind/util/MessageStrings.properties +++ b/src/gov/nasa/worldwind/util/MessageStrings.properties @@ -743,6 +743,7 @@ AbsentResourceList.MaxTriesLessThanOne=The specified maximum number of tries is AbsentResourceList.CheckIntervalLessThanZero=The specified check interval is less than 0 AbsentResourceList.RetryIntervalLessThanZero=The specified retry interval is less than 0 AbsentResourceList.MaximumListSizeLessThanOne=The requested maximum list size is less than 1 +AbsentResourceList.WCSDescribeCoverage=No coverage offering from WCS AVAAccessibleImpl.AttributeValueForKeyIsNotAString=Attribute value for key is not a String. Key {0} diff --git a/src/gov/nasa/worldwindx/examples/layermanager/ElevationModelManagerPanel.java b/src/gov/nasa/worldwindx/examples/layermanager/ElevationModelManagerPanel.java index f86d5677fe..424ced6d8a 100644 --- a/src/gov/nasa/worldwindx/examples/layermanager/ElevationModelManagerPanel.java +++ b/src/gov/nasa/worldwindx/examples/layermanager/ElevationModelManagerPanel.java @@ -127,6 +127,7 @@ protected boolean isUpToDate(WorldWindow wwd) if (!(wwd.getModel().getGlobe().getElevationModel() instanceof CompoundElevationModel)) { + if (this.modelPanels.size() == 0) return false; return this.modelPanels.get(0).getElevationModel() == wwd.getModel().getGlobe().getElevationModel(); } diff --git a/src/gov/nasa/worldwindx/examples/util/WCSCoveragePanel.java b/src/gov/nasa/worldwindx/examples/util/WCSCoveragePanel.java index c53919438d..5df2e439d2 100644 --- a/src/gov/nasa/worldwindx/examples/util/WCSCoveragePanel.java +++ b/src/gov/nasa/worldwindx/examples/util/WCSCoveragePanel.java @@ -100,7 +100,9 @@ protected void load() { e.printStackTrace(); Container c = WCSCoveragePanel.this.getParent(); - c.remove(WCSCoveragePanel.this); + if (c != null) + c.remove(WCSCoveragePanel.this); + JOptionPane.showMessageDialog((Component) wwd, "Unable to connect to server " + serverURI.toString(), "Server Error", JOptionPane.ERROR_MESSAGE); return; @@ -192,8 +194,10 @@ public void actionPerformed(ActionEvent actionEvent) // If the coverage is selected, add it to the WorldWindow's current model, else remove it from the model. if (((JCheckBox) actionEvent.getSource()).isSelected()) { - if (this.component == null) + if (this.component == null) { this.component = createComponent(coverageInfo.caps, coverageInfo); + if (this.component == null) return; + } updateComponent(this.component, true); } @@ -224,8 +228,18 @@ protected CoverageInfo createCoverageInfo(WCS100Capabilities caps, WCS100Coverag protected void updateComponent(Object component, boolean enable) { ElevationModel model = (ElevationModel) component; - CompoundElevationModel compoundModel = - (CompoundElevationModel) this.wwd.getModel().getGlobe().getElevationModel(); + CompoundElevationModel compoundModel; + + // Guarantee that we have a compound elevation model, so additional elevation models can be added. + ElevationModel em = this.wwd.getModel().getGlobe().getElevationModel(); + + if (!(em instanceof CompoundElevationModel)) { + compoundModel = new CompoundElevationModel(); + compoundModel.addElevationModel(em); + this.wwd.getModel().getGlobe().setElevationModel(compoundModel); + } else { + compoundModel = (CompoundElevationModel) em; + } if (enable) { From b1245968ec566d9588ff08e12a018b837967d6d9 Mon Sep 17 00:00:00 2001 From: Glenn Burkhardt Date: Wed, 7 Feb 2018 17:42:38 -0500 Subject: [PATCH 5/5] bug fix: request to WCS server should be limited to extent of data it has for the layer, or the request may fail. See https://forum.worldwindcentral.com/forum/world-wind-java-forums/development-help/158241-wcs-elevation-model-with-partial-data. --- src/gov/nasa/worldwind/terrain/BasicElevationModel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gov/nasa/worldwind/terrain/BasicElevationModel.java b/src/gov/nasa/worldwind/terrain/BasicElevationModel.java index b617a3cd7b..047bd0adb1 100644 --- a/src/gov/nasa/worldwind/terrain/BasicElevationModel.java +++ b/src/gov/nasa/worldwind/terrain/BasicElevationModel.java @@ -385,6 +385,7 @@ protected ElevationTile createTile(TileKey key) Angle minLongitude = ElevationTile.computeColumnLongitude(key.getColumn(), dLon, lonOrigin); Sector tileSector = new Sector(minLatitude, minLatitude.add(dLat), minLongitude, minLongitude.add(dLon)); + tileSector = levels.getSector().intersection(tileSector); return new ElevationTile(tileSector, level, key.getRow(), key.getColumn()); }