/*
Copyright (C) 2001, 2007 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.rpf;
import gov.nasa.worldwind.WWObjectImpl;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.formats.dds.DDSConverter;
import gov.nasa.worldwind.retrieve.RetrievalPostProcessor;
import gov.nasa.worldwind.retrieve.Retriever;
import gov.nasa.worldwind.util.Logging;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* @author dcollins
* @version $Id: RPFRetriever.java 4367 2008-02-05 19:00:58Z dcollins $
*/
class RPFRetriever extends WWObjectImpl implements Retriever
{
private volatile ByteBuffer byteBuffer;
private volatile int contentLength = 0;
private AtomicInteger contentLengthRead = new AtomicInteger(0);
private volatile String state = RETRIEVER_STATE_NOT_STARTED;
private volatile String contentType;
private long submitTime;
private long beginTime;
private long endTime;
private int connectTimeout = -1;
private int readTimeout = -1;
private int staleRequestLimit = -1;
private final RPFGenerator.RPFServiceInstance service;
private final URL url;
private final RetrievalPostProcessor postProcessor;
private int responseCode;
public static final int RESPONSE_CODE_OK = 1;
public static final int RESPONSE_CODE_NO_CONTENT = 2;
public RPFRetriever(RPFGenerator.RPFServiceInstance service, URL url, RetrievalPostProcessor postProcessor)
{
if (service == null)
{
String message = "Service is null";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (url == null)
{
String message = Logging.getMessage("nullValue.URLIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (postProcessor == null)
{
String message = Logging.getMessage("nullValue.PostProcessorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.service = service;
this.url = url;
this.postProcessor = postProcessor;
}
public final ByteBuffer getBuffer()
{
return this.byteBuffer;
}
public final int getContentLength()
{
return this.contentLength;
}
public final int getContentLengthRead()
{
return this.contentLengthRead.get();
}
protected void setContentLengthRead(int length)
{
this.contentLengthRead.set(length);
}
public final String getName()
{
return this.url.toString();
}
public final String getState()
{
return this.state;
}
public final String getContentType()
{
return this.contentType;
}
public long getSubmitTime()
{
return this.submitTime;
}
public void setSubmitTime(long submitTime)
{
this.submitTime = submitTime;
}
public long getBeginTime()
{
return this.beginTime;
}
public void setBeginTime(long beginTime)
{
this.beginTime = beginTime;
}
public long getEndTime()
{
return this.endTime;
}
public void setEndTime(long endTime)
{
this.endTime = endTime;
}
public int getConnectTimeout()
{
return this.connectTimeout;
}
public void setConnectTimeout(int connectTimeout)
{
this.connectTimeout = connectTimeout;
}
public int getReadTimeout()
{
return this.readTimeout;
}
public void setReadTimeout(int readTimeout)
{
this.readTimeout = readTimeout;
}
public int getStaleRequestLimit()
{
return this.staleRequestLimit;
}
public void setStaleRequestLimit(int staleRequestLimit)
{
this.staleRequestLimit = staleRequestLimit;
}
public final RPFGenerator.RPFServiceInstance getService()
{
return this.service;
}
public final URL getURL()
{
return this.url;
}
public final RetrievalPostProcessor getPostProcessor()
{
return this.postProcessor;
}
public int getResponseCode()
{
return this.responseCode;
}
public final Retriever call() throws Exception
{
if (interrupted())
return this;
try
{
setState(RETRIEVER_STATE_STARTED);
// Simulate connected state.
if (!interrupted())
setState(RETRIEVER_STATE_CONNECTING);
if (!interrupted())
{
setState(RETRIEVER_STATE_READING);
this.byteBuffer = read();
}
if (!interrupted())
setState(RETRIEVER_STATE_SUCCESSFUL);
}
catch (Exception e)
{
setState(RETRIEVER_STATE_ERROR);
Logging.logger().log(Level.SEVERE,
Logging.getMessage("URLRetriever.ErrorAttemptingToRetrieve", this.url.toString()), e);
}
finally
{
end();
}
return this;
}
private void setState(String state)
{
String oldState = this.state;
this.state = state;
this.firePropertyChange(AVKey.RETRIEVER_STATE, oldState, this.state);
}
private boolean interrupted()
{
if (Thread.currentThread().isInterrupted())
{
setState(RETRIEVER_STATE_INTERRUPTED);
String message = Logging.getMessage("URLRetriever.RetrievalInterruptedFor", this.url.toString());
Logging.logger().fine(message);
return true;
}
return false;
}
private void end() throws Exception
{
try
{
if (this.postProcessor != null)
{
this.byteBuffer = this.postProcessor.run(this);
}
}
catch (Exception e)
{
setState(RETRIEVER_STATE_ERROR);
Logging.logger().log(Level.SEVERE,
Logging.getMessage("URLRetriever.ErrorPostProcessing", this.url.toString()), e);
throw e;
}
}
private ByteBuffer read() throws Exception
{
ByteBuffer buffer = this.doRead(this.service, this.url);
if (buffer == null)
this.contentLength = 0;
return buffer;
}
protected ByteBuffer doRead(RPFGenerator.RPFServiceInstance service, URL url) throws Exception
{
ByteBuffer buffer = null;
BufferedImage bufferedImage = service.serviceRequest(url);
if (bufferedImage != null)
{
// TODO: format parameter should determine image type
buffer = DDSConverter.convertToDxt3(bufferedImage);
if (buffer != null)
{
int length = buffer.limit();
this.contentType = "image/dds";
this.contentLength = length;
setContentLengthRead(length);
}
}
// TODO: service should provide response code
this.responseCode = buffer != null ? RESPONSE_CODE_OK : RESPONSE_CODE_NO_CONTENT;
return buffer;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final RPFRetriever that = (RPFRetriever) o;
// Retrievers are considered identical if they are for the same URL. This convention is used by the
// retrieval service to filter out duplicate retreival requests.
return !(url != null ? !url.toString().contentEquals(that.url.toString()) : that.url != null);
}
@Override
public int hashCode()
{
int result;
result = (url != null ? url.hashCode() : 0);
return result;
}
@Override
public String toString()
{
return this.getName() != null ? this.getName() : super.toString();
}
}