/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.cache.SessionCache;
import gov.nasa.worldwind.ogc.wms.WMSCapabilities;
import gov.nasa.worldwind.retrieve.*;
import java.beans.PropertyChangeListener;
import java.nio.BufferUnderflowException;
/**
* A collection of utility methods for retrieving and managing data in the {@link SessionCache}.
*
* @author dcollins
* @version $Id: SessionCacheUtils.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class SessionCacheUtils
{
/**
* Retrieves the contents of a specified {@link java.net.URL}. If successful, this places the URL
* contents in a specified session cache with a specified key. This either marks the resource as available or
* missing, depending on whether the retrieval succeeds or fails. Finally, this optionally notifies the caller that
* the retrieval has succeeded by firing a property change event. If either the property listener or property name
* are null, that functionality is disabled.
*
* @param url the URL contents to retrieve.
* @param cache the cache which receives the retrieved data.
* @param cacheKey the cache key which identifies where the retrieved data is placed in the session
* cache.
* @param absentResourceList the absent resource list to update.
* @param resourceID the resource ID to use in the absent resource list.
* @param propertyListener the property change listener which is fired when the retrieved data is available.
* @param propertyName the property name to fire when retrieved data is available.
*
* @throws IllegalArgumentException if any of the url, retrieval service, cache, or cache key are null.
*/
public static void retrieveSessionData(java.net.URL url, SessionCache cache, Object cacheKey,
AbsentResourceList absentResourceList, long resourceID, PropertyChangeListener propertyListener,
String propertyName)
{
if (url == null)
{
String message = Logging.getMessage("nullValue.URLIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (cache == null)
{
String message = Logging.getMessage("nullValue.CacheIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (cacheKey == null)
{
String message = Logging.getMessage("nullValue.CacheKeyIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (WorldWind.getNetworkStatus().isHostUnavailable(url))
{
if (absentResourceList != null)
absentResourceList.markResourceAbsent(resourceID);
return;
}
SessionCacheRetrievalPostProcessor postProcessor = new SessionCacheRetrievalPostProcessor(cache, cacheKey,
absentResourceList, resourceID, propertyListener, propertyName);
postProcessor.setName(url.toString());
Retriever retriever = URLRetriever.createRetriever(url, postProcessor);
try
{
retriever.call();
}
catch (Exception e)
{
String message = Logging.getMessage("layers.TiledImageLayer.ExceptionRetrievingResources", url.toString());
Logging.logger().severe(message);
}
}
/**
* Checks a session cache for a specified key, and if present attempts to interpret the cache entry as a {@link
* WMSCapabilities} document. If the key does not exist in the cache, or the cache entry cannot be interpreted as a
* Capabilities document, this returns null. If the entry exists, but must be converted to a Capabilities document,
* this overrides the previous cache entry with the the newly converted Capabilities.
*
* @param cache the session cache.
* @param cacheKey the key to identify the object in the session cache.
* @param name the name to use in logging messages.
*
* @return the Capabilities document in the session cache, or null if either the key does not match an entry in the
* cache, or that entry cannot be interpreted as a Capabilities document.
*
* @throws IllegalArgumentException if either the cache or cache key are null.
*/
public static WMSCapabilities getSessionCapabilities(SessionCache cache, Object cacheKey, String name)
{
if (cache == null)
{
String message = Logging.getMessage("nullValue.CacheIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (cacheKey == null)
{
String message = Logging.getMessage("nullValue.CacheKeyIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Object o = cache.get(cacheKey);
if (o == null)
return null;
// The cache entry exists, and is already a Capabilities document.
if (o instanceof WMSCapabilities)
return (WMSCapabilities) o;
// The cache entry exists, but is not a Capabilities document. Attempt to parse the Capabilities docuemnt,
// by treating the current cache entry as a source.
WMSCapabilities caps = parseCapabilities(o, name);
if (caps == null)
return null;
// If the parsing succeeded, then overwrite the existing cache entry with the newly created Capabilities.
cache.put(cacheKey, caps);
return caps;
}
/**
* Checks a session cache for a specified key, and if present attempts to interpret the cache entry as a {@link
* WMSCapabilities} document. If the key does not map to a Capabilities document for any reason, this attempts to
* asynchronously retrieve the Capabilities from a specified URL, and returns null.
*
* @param url the URL contents to retrieve.
* @param cache the session cache.
* @param cacheKey the key to identify the object in the session cache.
* @param absentResourceList the absent resource list to update.
* @param resourceID the resource ID to use in the absent resource list.
* @param propertyListener the property change listener which is fired when the retrieved data is available.
* @param propertyName the property name to fire when retrieved data is available.
*
* @return the Capabilities document in the session cache, or null if the document is not in the cache.
*
* @throws IllegalArgumentException if either the url, retrieval service, cache or cache key are null.
*/
public static WMSCapabilities getOrRetrieveSessionCapabilities(java.net.URL url, SessionCache cache,
Object cacheKey, AbsentResourceList absentResourceList, long resourceID,
PropertyChangeListener propertyListener, String propertyName)
{
if (url == null)
{
String message = Logging.getMessage("nullValue.URLIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (cache == null)
{
String message = Logging.getMessage("nullValue.CacheIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (cacheKey == null)
{
String message = Logging.getMessage("nullValue.CacheKeyIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
WMSCapabilities caps = getSessionCapabilities(cache, cacheKey, url.toString());
if (caps != null)
return caps;
retrieveSessionData(url, cache, cacheKey, absentResourceList, resourceID, propertyListener, propertyName);
// Try to get the caps after the retrieval attempt.
caps = getSessionCapabilities(cache, cacheKey, url.toString());
if (caps != null)
return caps;
return null;
}
protected static WMSCapabilities parseCapabilities(Object source, String name)
{
if (source == null)
{
String message = Logging.getMessage("nullValue.SourceIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
java.io.InputStream inputStream = null;
try
{
WMSCapabilities caps = new WMSCapabilities(source);
return caps.parse();
}
catch (Exception e)
{
String message = Logging.getMessage("generic.CannotParseCapabilities", name);
// beg modif bill
/*
* avoiding message like the one below:
*
* 15 août 2014 15:49:53 gov.nasa.worldwind.util.SessionCacheUtils parseCapabilities
GRAVE: Unable to parse capabilities http://worldwind26.arc.nasa.gov/wms?EXCEPTIONS=application/vnd.ogc.se_xml&REQUEST=GetCapabilities&SERVICE=WMS&VERSION=1.3.0
java.nio.BufferUnderflowException
>> info: valueStarted
at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:127)
at java.nio.ByteBuffer.get(ByteBuffer.java:675)
at gov.nasa.worldwind.util.WWIO.getInputStreamFromByteBuffer(WWIO.java:1615)
at gov.nasa.worldwind.util.WWXML.openEventReader(WWXML.java:501)
at gov.nasa.worldwind.util.WWXML.openEventReader(WWXML.java:464)
at gov.nasa.worldwind.ogc.OGCCapabilities.createReader(OGCCapabilities.java:91)
at gov.nasa.worldwind.ogc.OGCCapabilities.<init>(OGCCapabilities.java:70)
at gov.nasa.worldwind.ogc.wms.WMSCapabilities.<init>(WMSCapabilities.java:60)
at gov.nasa.worldwind.util.SessionCacheUtils.parseCapabilities(SessionCacheUtils.java:207)
at gov.nasa.worldwind.util.SessionCacheUtils.getSessionCapabilities(SessionCacheUtils.java:130)
at gov.nasa.worldwind.util.SessionCacheUtils.getOrRetrieveSessionCapabilities(SessionCacheUtils.java:181)
at gov.nasa.worldwind.terrain.BasicElevationModel.retrieveResources(BasicElevationModel.java:1791)
at gov.nasa.worldwind.terrain.BasicElevationModel$3.run(BasicElevationModel.java:1881)
at java.lang.Thread.run(Thread.java:662)
*/
if (e instanceof BufferUnderflowException)
{
String strWarningWhat = e.getMessage();
if (strWarningWhat == null)
{
strWarningWhat = "strWarning == null";
}
String strWarningContents = "WorldWind warning, got excBufferUnderflow:";
strWarningContents += "\n class: " + SessionCacheUtils.class.getName();
strWarningContents += "\n method: " + "parseCapabilities(...)";
strWarningContents += "\n what: " + strWarningWhat;
strWarningContents += "\n\n, ignoring!";
System.err.println("WorldWind warning, got excBufferUnderflow, e..getMessage()=\n" + strWarningContents);
}
else
// end modif bill
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
// end modif bill
}
finally
{
WWIO.closeStream(inputStream, name);
}
return null;
}
}