/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.animate;
import java.awt.image.RenderedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.wms.DefaultWebMapService;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WebMap;
import org.geoserver.wms.WebMapService;
import org.geoserver.wms.map.GetMapKvpRequestReader;
import org.geoserver.wms.map.RenderedImageMap;
import org.geotools.styling.Style;
import com.vividsolutions.jts.geom.Envelope;
/**
* GIF Animated reflecting service.
* <p>
* This is the main entry point to easily create animations.<br/>
* The reflector is able to parse incomplete WMS GetMap requests containing at least:<br/>
* <ul>
* <li>A multivalued request supported output format</li>
* <li>An "aparam" animation parameter</li>
* <li>An "avalues" list of values for the animation parameter</li>
* </ul>
*
* </p>
*
* @author Alessio Fabiani, GeoSolutions S.A.S., alessio.fabiani@geo-solutions.it
* @author Andrea Aime, GeoSolutions S.A.S., andrea.aime@geo-solutions.it
*/
public class Animator {
private static Logger LOGGER = org.geotools.util.logging.Logging
.getLogger("org.vfny.geoserver.wms.responses.map.anim");
/**
* default 'format' value
* - used if no output format has been found on the GetMap request
**/
public static final String GIF_ANIMATED_FORMAT = "image/gif;subtype=animated";
/**
* web map service
*/
WebMapService wms;
/**
* The WMS configuration
*/
WMS wmsConfiguration;
/**
* The prototype Constructor
*
* @param wms
* @param wmsConfiguration
*/
public Animator(WebMapService wms, WMS wmsConfiguration) {
this.wms = wms;
this.wmsConfiguration = wmsConfiguration;
}
/**
* Produce method.
* Returns the full animation WebMap request.
*
* @param request
* @param wms
* @param wmsConfiguration
*
*/
public static org.geoserver.wms.WebMap produce(GetMapRequest request, WebMapService wms,
WMS wmsConfiguration) throws Exception {
// initializing the catalog of frames. The method analyzes the main request looking for
// 'aparam' and 'avalues' and initializes the list of frames to be produced.
FrameCatalog frameCatalog = initRequestManager(request, wms, wmsConfiguration);
if (frameCatalog == null) {
throw new RuntimeException("Animator initialization error!");
}
// Setup AnimGifOUTputFormat as default if not specified
if (request.getFormat() == null) {
request.setFormat(GIF_ANIMATED_FORMAT);
}
// if we have a case of layers being the param, stick the first value into the request
if(frameCatalog.getParameter().equalsIgnoreCase("LAYERS")) {
List<String> layers0 = Arrays.asList(frameCatalog.getValues()[0].replaceAll("\\\\,", ",").split("\\s*,\\s*"));
LayerParser parser = new LayerParser(wmsConfiguration);
List<MapLayerInfo> layers = parser.parseLayerInfos(layers0,
request.getRemoteOwsURL(), request.getRemoteOwsType());
request.setLayers(layers);
}
// set rest of the wms defaults
request = DefaultWebMapService.autoSetMissingProperties(request);
// if we have a case of layers being the param, we should also try to get uniform
// width and height and bbox
if(frameCatalog.getParameter().equalsIgnoreCase("LAYERS")) {
Envelope bbox = request.getBbox();
request.getRawKvp().put("BBOX", bbox.getMinX() + "," + request.getBbox().getMinY() + ","
+ request.getBbox().getMaxX() + "," + request.getBbox().getMaxY());
request.getRawKvp().put("WIDTH", String.valueOf(request.getWidth()));
request.getRawKvp().put("HEIGHT", String.valueOf(request.getHeight()));
}
// initializing the catalog visitor. This takes care of producing single
// RenderedImages.
FrameCatalogVisitor visitor = new FrameCatalogVisitor();
frameCatalog.getFrames(visitor);
RenderedImage imageList = visitor.produce(frameCatalog.getWmsConfiguration());
// run a single getmap to get the right mime type and map context
WebMap wmsResponse = wms.getMap(request);
return new RenderedImageMap(((RenderedImageMap) wmsResponse).getMapContext(), imageList,
wmsResponse.getMimeType());
}
/**
* Initializes the Animator engine.
*
* @param request
* @param wmsConfiguration
*
*/
private static FrameCatalog initRequestManager(GetMapRequest request, WebMapService wms, WMS wmsConfiguration) {
return new FrameCatalog(request, wms, wmsConfiguration);
}
/**
* A helper that avoids duplicating the code to parse a layer
* @author Andrea Aime - GeoSolutions
*/
static class LayerParser extends GetMapKvpRequestReader {
public LayerParser(WMS wmsConfiguration) {
super(wmsConfiguration);
}
public List<MapLayerInfo> parseLayerInfos(List<String> requestedLayerNames, URL remoteOwsUrl,
String remoteOwsType) throws Exception {
List requestedLayerInfos = super.parseLayers(requestedLayerNames, remoteOwsUrl, remoteOwsType);
List<MapLayerInfo> layers = new ArrayList<MapLayerInfo>();
for (Object o : requestedLayerInfos) {
if (o instanceof LayerInfo) {
layers.add(new MapLayerInfo((LayerInfo) o));
} else if (o instanceof LayerGroupInfo) {
for (LayerInfo l : ((LayerGroupInfo) o).layers()) {
layers.add(new MapLayerInfo(l));
}
} else if (o instanceof MapLayerInfo) {
// it was a remote OWS layer, add it directly
layers.add((MapLayerInfo) o);
}
}
return layers;
}
}
}