/**
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author Arne Kepp, The Open Planning Project, Copyright 2009
*
*/
package org.geowebcache.conveyor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.util.Collections;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.io.ByteArrayResource;
import org.geowebcache.io.Resource;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.layer.TileResponseReceiver;
import org.geowebcache.mime.MimeType;
import org.geowebcache.storage.StorageBroker;
import org.geowebcache.storage.StorageException;
import org.geowebcache.storage.TileObject;
/**
* Represents a request for a tile and carries the information needed to complete it.
*/
public class ConveyorTile extends Conveyor implements TileResponseReceiver {
private static Log log = LogFactory.getLog(org.geowebcache.conveyor.ConveyorTile.class);
// Shared request information, this is stored by the cache key
// protected long[] tileIndex = null;
// protected SRS srs = null;
protected String gridSetId = null;
protected GridSubset gridSubset = null;
protected TileLayer tileLayer = null;
TileObject stObj = null;
private Map<String, String> fullParameters; // TODO: why is this "full"? It seems to only relate to filtering
private boolean isMetaTileCacheOnly;
public ConveyorTile(StorageBroker sb, String layerId, HttpServletRequest servletReq,
HttpServletResponse servletResp) {
super(layerId, sb, servletReq, servletResp);
}
/**
* @deprecated as of 1.2.5, use
* {@link #ConveyorTile(StorageBroker, String, String, long[], MimeType, Map, HttpServletRequest, HttpServletResponse)}
* instead. This method just calls it with the provided {@code fullParameters} and
* will be removed soon
*/
@Deprecated
public ConveyorTile(StorageBroker sb, String layerId, String gridSetId, long[] tileIndex,
MimeType mimeType, Map<String, String> fullParameters,
Map<String, String> modifiedParameters, HttpServletRequest servletReq,
HttpServletResponse servletResp) {
this(sb, layerId, gridSetId, tileIndex, mimeType, fullParameters, servletReq, servletResp);
}
/**
* This constructor is used for an incoming request, the data is then added by the cache
*/
public ConveyorTile(StorageBroker sb, String layerId, String gridSetId, long[] tileIndex,
MimeType mimeType, Map<String, String> filteringParameters,
HttpServletRequest servletReq, HttpServletResponse servletResp) {
super(layerId, sb, servletReq, servletResp);
this.gridSetId = gridSetId;
long[] idx = new long[3];
if (tileIndex != null) {
idx[0] = tileIndex[0];
idx[1] = tileIndex[1];
idx[2] = tileIndex[2];
}
super.mimeType = mimeType;
this.fullParameters = filteringParameters;
stObj = TileObject.createQueryTileObject(layerId, idx, gridSetId, mimeType.getFormat(),
filteringParameters);
}
public Map<String, String> getFullParameters() {
if (fullParameters == null) {
return Collections.emptyMap();
}
return fullParameters;
}
public TileLayer getLayer() {
return this.tileLayer;
}
public void setTileLayer(TileLayer layer) {
this.tileLayer = layer;
}
public TileLayer getTileLayer() {
return tileLayer;
}
/**
* The time that the stored tile resource was created
* @return
*/
public long getTSCreated() {
return stObj.getCreated();
}
public int getStatus() {
return (int) status;
}
public void setStatus(int status) {
this.status = (long) status;
}
public String getErrorMessage() {
return this.errorMsg;
}
public void setErrorMessage(String errorMessage) {
this.errorMsg = errorMessage;
}
public Map<String, String> getParameters() {
return ((TileObject) stObj).getParameters();
}
public long[] getTileIndex() {
return stObj.getXYZ();
}
public synchronized GridSubset getGridSubset() {
if (gridSubset == null) {
gridSubset = tileLayer.getGridSubset(gridSetId);
}
return gridSubset;
}
public String getGridSetId() {
return gridSetId;
}
public void setGridSetId(String gridSetId) {
this.gridSetId = gridSetId;
}
/**
* @deprecated as of 1.2.4a, use {@link #getBlob()}, keeping it for backwards compatibility as
* there are geoserver builds pegged at a given geoserver revision but building gwc
* from trunk. Ok to remove at 1.2.5
*/
@Deprecated
public byte[] getContent() {
Resource blob = getBlob();
if (blob instanceof ByteArrayResource) {
return ((ByteArrayResource) blob).getContents();
}
ByteArrayOutputStream out = new ByteArrayOutputStream((int) blob.getSize());
try {
blob.transferTo(Channels.newChannel(out));
return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Resource getBlob() {
return stObj.getBlob();
}
/**
* @deprecated as of 1.2.4a, use {@link #setBlob(Resource)}, keeping it for backwards
* compatibility as there are geoserver builds pegged at a given geoserver revision
* but building gwc from trunk. Ok to remove at 1.2.5
*/
@Deprecated
public void setContent(byte[] payload) {
setBlob(new ByteArrayResource(payload));
}
public void setBlob(Resource payload) {
stObj.setBlob(payload);
}
public TileObject getStorageObject() {
return stObj;
}
public boolean persist() throws GeoWebCacheException {
try {
return storageBroker.put((TileObject) stObj);
} catch (StorageException e) {
throw new GeoWebCacheException(e);
}
}
public boolean retrieve(long maxAge) throws GeoWebCacheException {
try {
if (isMetaTileCacheOnly) {
boolean cached = storageBroker.getTransient((TileObject) stObj);
this.setCacheResult(cached ? CacheResult.HIT : CacheResult.MISS);
return cached;
}
boolean ret = storageBroker.get((TileObject) stObj);
// Do we use expiration, and if so, is the tile recent enough ?
if (ret && maxAge > 0 && stObj.getCreated() + maxAge < System.currentTimeMillis()) {
ret = false;
}
if (ret) {
this.setCacheResult(CacheResult.HIT);
} else {
this.setCacheResult(CacheResult.MISS);
}
return ret;
} catch (StorageException se) {
log.warn(se.getMessage());
return false;
}
}
public String toString() {
StringBuilder str = new StringBuilder();
str.append("ConveyorTile[");
long[] idx = stObj.getXYZ();
if (idx != null && idx.length == 3) {
str.append("{" + idx[0] + "," + idx[1] + "," + idx[2] + "} ");
}
if (getLayer() != null) {
str.append(getLayerId()).append(" ");
}
if (this.gridSetId != null) {
str.append(gridSetId).append(" ");
}
if (this.mimeType != null) {
str.append(this.mimeType.getFormat());
}
str.append(']');
return str.toString();
}
public String getParametersId() {
return stObj.getParametersId();
}
public void setMetaTileCacheOnly(boolean b) {
this.isMetaTileCacheOnly = b;
}
public boolean isMetaTileCacheOnly() {
return isMetaTileCacheOnly;
}
}