package org.geotools.tile.nasa;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.geotools.tile.TileMapInfo;
import org.geotools.tile.TileSet;
import org.geotools.tile.ZoomLevel;
import org.jdom.Element;
/**
* Captures the different ways of accessing content used
* by WorldWind.
*/
public abstract class Accessor {
/** Name of Layer using this accessor */
abstract String getName();
/** Name of Layer using this accessor */
abstract URI getIdentifier();
/** Non null RenderedImage if data exists at that location */
abstract RenderedImage tileImage( TileSet tileset, int row, int col ) throws IOException;
/**
* Create an accessor for the provided layer.
* <p>
* Currently supports ImageAccessor.
* </p>
* @param element
* @return
*/
static Accessor create( Element element ){
if( element.getChild( "ImageAccessor") != null){
Element imageAccessor = element.getChild("ImageAccessor");
if( imageAccessor.getChild("ImageTileService") != null){
return createImageTileAccessor( imageAccessor.getChild("ImageTileService") );
}
else if( imageAccessor.getChild("WMSAccessor") != null){
return createWMSAccessor( imageAccessor.getChild("WMSAccessor") );
}
}
return null;
}
private static Accessor createImageTileAccessor( final Element imageTileService ) {
final String server = imageTileService.getChildText("ServerUrl");
final String data = imageTileService.getChildText("DataSetName");
try {
final String name = data;
final URI id = new URI( server + "#" + data );
return new Accessor(){
String getName() {
return name;
}
URI getIdentifier() {
return id;
}
public RenderedImage tileImage( TileSet tileset, int row, int col ) throws IOException {
URL request;
request = requestURL( tileset, row, col );
if( request == null ) return null; // no data here move on
try {
//BufferedImage image = ImageIO.read( request.openStream() );
//return JAI.create( "tile"+row+"x"+col, request );
ImageInputStream input = openImageInput( request );
if( input == null ){
return null; // request invalid
}
ImageReader jpeg = ImageIO.getImageReadersByFormatName("jpeg").next();
jpeg.setInput( input, true );
return jpeg.read(0,null);
}
catch( IOException io){
System.out.println( io.getMessage() + "for request:"+request);
return null;
}
catch( NoClassDefFoundError format ){
System.out.println("Unknown format:"+request );
return null;
}
}
/**
* Set up the request url.
*
* @param tileset
* @param row
* @param col
* @return
* @throws IOException
*/
private URL requestURL( TileSet tileset, int row, int col ) throws IOException {
int level = levelNumber( tileset );
String request =
MessageFormat.format("{0}?T={1}&L={2}&X={3}&Y={4}",
new Object[]{server, data,
new Integer( level ), new Integer(col), new Integer(row)});
return new URL( request );
}
private int levelNumber( TileSet tileset ) {
TileMapInfo info = tileset.getTileMap().getInfo();
ZoomLevel zoomLevel = tileset.getZoomLevel();
Set set = info.getZoomLevels();
int level = 0;
for( Iterator i = set.iterator(); i.hasNext(); level++ ) {
if (zoomLevel.equals(i.next())) {
return level;
}
}
return -1;
}
};
} catch (URISyntaxException e) {
return null;
}
}
/**
* This method actually checks the connection header information first...
* </p>
* Sample invalid header: <b>http://worldwind25.arc.nasa.gov/tile/tile.aspx?T=105&L=0&X=63&Y=22</b>
* <pre><code>
* HTTP/1.1 204 No Content
* Date: Wed, 22 Nov 2006 01:48:51 GMT
* Server: Microsoft-IIS/6.0
* X-Powered-By: ASP.NET
* X-AspNet-Version: 1.1.4322
* Set-Cookie: ASP.NET_SessionId=smi5d055xvtdcx45ltxrbcjv; path=/
* Cache-Control: private
* Content-Length: 24
*
* No data for this region.
* </code></pre>
*
* This method should be replaced with a peek at the connection,
* and then pass the connection onto JAI.create ...
* @param request
* @return URL or null if could not connect
*
static URL checkRequest( String request ){
URL url;
try {
url = new URL( request );
} catch (MalformedURLException e) {
throw new RuntimeException( e );
}
if( "http".equalsIgnoreCase(url.getProtocol())){
// check connection header
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) url.openConnection();
System.out.println( "HTTP "+connection.getResponseCode()+":" +request );
if( connection.getResponseCode() == 200 ){
return url; // okay
}
if( connection.getResponseCode() == 204 ){
return null; // we must be "No data for this region.";
}
} catch (IOException e) {
System.out.println("No content:"+request);
System.out.println( e );
return null;
}
}
return url;
}*/
/**
* This method actually checks the connection header information first...
* </p>
* Sample invalid header: <b>http://worldwind25.arc.nasa.gov/tile/tile.aspx?T=105&L=0&X=63&Y=22</b>
* <pre><code>
* HTTP/1.1 204 No Content
* Date: Wed, 22 Nov 2006 01:48:51 GMT
* Server: Microsoft-IIS/6.0
* X-Powered-By: ASP.NET
* X-AspNet-Version: 1.1.4322
* Set-Cookie: ASP.NET_SessionId=smi5d055xvtdcx45ltxrbcjv; path=/
* Cache-Control: private
* Content-Length: 24
*
* No data for this region.
* </code></pre>
* @return ImageInputStream (or null if No data for this region)
*/
static ImageInputStream openImageInput( URL url ) throws IOException {
if( "http".equalsIgnoreCase(url.getProtocol())){
// check connection header
HttpURLConnection connection = null;
connection = (HttpURLConnection) url.openConnection();
System.out.println( "HTTP "+connection.getResponseCode()+":" +url );
if( connection.getResponseCode() == 204 ){
connection.disconnect();
return null; // we must be "No data for this region.";
}
return ImageIO.createImageInputStream(connection.getInputStream());
}
return ImageIO.createImageInputStream( url.openStream() );
}
private static Accessor createWMSAccessor( final Element wmsAccessor ) {
String server = wmsAccessor.getChildText("ServerGetMapUrl");
String data = wmsAccessor.getChildText("global_mosaic");
try {
final String name = data;
final URI id = new URI( server + "#" + data );
return new Accessor(){
String getName() {
return name;
}
URI getIdentifier() {
return id;
}
@Override
RenderedImage tileImage( TileSet tileset, int row, int col ) throws IOException {
throw new IOException("No Content");
}
};
} catch (URISyntaxException e) {
return null;
}
}
}