org.mapfish.print.servlet.oldapi.OldAPIRequestConverter Maven / Gradle / Ivy
Show all versions of print-lib Show documentation
package org.mapfish.print.servlet.oldapi;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.config.OldApiConfig;
import org.mapfish.print.config.Template;
import org.mapfish.print.processor.Processor;
import org.mapfish.print.processor.jasper.LegendProcessor;
import org.mapfish.print.processor.jasper.TableProcessor;
import org.mapfish.print.processor.map.CreateMapProcessor;
import org.mapfish.print.servlet.MapPrinterServlet;
import org.mapfish.print.wrapper.PArray;
import org.mapfish.print.wrapper.PObject;
import org.mapfish.print.wrapper.json.PJsonArray;
import org.mapfish.print.wrapper.json.PJsonObject;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static org.mapfish.print.Constants.JSON_LAYOUT_KEY;
import static org.mapfish.print.Constants.OUTPUT_FILENAME_KEY;
import static org.mapfish.print.servlet.MapPrinterServlet.JSON_OUTPUT_FORMAT;
/**
* Converter for print requests of the old API.
*/
public final class OldAPIRequestConverter {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(OldAPIRequestConverter.class);
private static final Set NON_CUSTOM_PARAMS = Sets.newHashSet(
"units", "srs", "layout", "dpi", "layers", "pages", "legends",
"geodetic", "outputFilename", "outputFormat", "app");
private OldAPIRequestConverter() {
}
/**
* Converts a print request of the old API into the new request format.
*
* Note that the converter does not support all features of the old API, for example only requests
* containing a single map are supported.
*
* @param oldRequest the request in the format of the old API
* @param configuration the configuration
*/
public static PJsonObject convert(final PJsonObject oldRequest, final Configuration configuration)
throws JSONException {
final String layout = oldRequest.getString(JSON_LAYOUT_KEY);
if (configuration.getTemplate(layout) == null) {
throw new IllegalArgumentException("Layout '" + layout + "' is not configured");
}
final JSONObject request = new JSONObject();
request.put(JSON_LAYOUT_KEY, oldRequest.getString(JSON_LAYOUT_KEY));
if (oldRequest.has(OUTPUT_FILENAME_KEY)) {
request.put(OUTPUT_FILENAME_KEY, oldRequest.getString(OUTPUT_FILENAME_KEY));
}
if (oldRequest.has(JSON_OUTPUT_FORMAT)) {
request.put(JSON_OUTPUT_FORMAT, oldRequest.getString(JSON_OUTPUT_FORMAT));
}
request.put(MapPrinterServlet.JSON_ATTRIBUTES,
getAttributes(oldRequest, configuration.getTemplate(layout)));
return new PJsonObject(request, "spec");
}
private static JSONObject getAttributes(final PJsonObject oldRequest, final Template template)
throws JSONException {
final JSONObject attributes = new JSONObject();
setMapAttribute(attributes, oldRequest, template);
setTableAttribute(attributes, oldRequest, template);
setLegendAttribute(attributes, oldRequest, template);
// TODO legends, scales, ...
// copy custom parameters
Iterator keys = oldRequest.keys();
while (keys.hasNext()) {
String key = keys.next();
if (!NON_CUSTOM_PARAMS.contains(key)) {
attributes.put(key, oldRequest.getInternalObj().get(key));
}
}
return attributes;
}
private static void setMapAttribute(
final JSONObject attributes,
final PJsonObject oldRequest, final Template template) throws JSONException {
final CreateMapProcessor mapProcessor = getMapProcessor(template);
final PJsonObject oldMapPage = (PJsonObject) getOldMapPage(oldRequest);
if (mapProcessor == null) {
if (oldMapPage == null) {
// no map, no work
return;
} else {
LOGGER.warn(
"The request json data has attribute information for creating the map but config " +
"does not have a" +
"map attribute. Check that the request and the config.yaml are correct.");
return;
}
} else if (oldMapPage == null) {
LOGGER.warn("The request json data does not have attribute information for creating the map." +
" Check that the request and the config.yaml are correct.");
return;
}
String mapAttributeName = "map";
if (mapProcessor.getInputMapperBiMap().containsValue("map")) {
mapAttributeName = mapProcessor.getInputMapperBiMap().inverse().get("map");
}
final JSONObject map = new JSONObject();
attributes.put(mapAttributeName, map);
if (oldRequest.has("srs")) {
map.put("projection", oldRequest.getString("srs"));
}
if (oldRequest.has("dpi")) {
map.put("dpi", oldRequest.getInt("dpi"));
}
if (oldMapPage.has("rotation")) {
// rotation must be inverted
map.put("rotation", -oldMapPage.getDouble("rotation"));
}
if (oldMapPage.has("bbox")) {
map.put("bbox", oldMapPage.getInternalObj().getJSONArray("bbox"));
} else if (oldMapPage.has("center") && oldMapPage.has("scale")) {
map.put("center", oldMapPage.getInternalObj().getJSONArray("center"));
map.put("scale", oldMapPage.getDouble("scale"));
}
setMapLayers(map, oldRequest, template.getConfiguration().getOldApi());
}
private static CreateMapProcessor getMapProcessor(final Template template) {
CreateMapProcessor mapProcessor = null;
for (Processor, ?> processor: template.getProcessors()) {
if (processor instanceof CreateMapProcessor) {
if (mapProcessor == null) {
mapProcessor = (CreateMapProcessor) processor;
} else {
throw new UnsupportedOperationException("Template contains "
+
"more than one map configuration. The " +
"legacy API "
+ "supports only one map per template.");
}
}
}
return mapProcessor;
}
private static PObject getOldMapPage(final PJsonObject oldRequest) {
final PArray pages = oldRequest.getArray("pages");
PObject mapPage = null;
for (int i = 0; i < pages.size(); i++) {
final PObject page = pages.getObject(i);
if (isMapPage(page)) {
if (mapPage == null) {
mapPage = page;
} else {
throw new UnsupportedOperationException("Request contains "
+
"more than one page with a map. The " +
"legacy API "
+ "supports only one map per report.");
}
}
}
return mapPage;
}
private static boolean isMapPage(final PObject page) {
if (page.has("bbox") || (page.has("center") && page.has("scale"))) {
return page.optBool("showMap", true);
}
return false;
}
private static void setMapLayers(
final JSONObject map, final PJsonObject oldRequest, final OldApiConfig oldApi)
throws JSONException {
final JSONArray layers = new JSONArray();
map.put("layers", layers);
if (!oldRequest.has("layers")) {
return;
}
PArray oldLayers = oldRequest.getArray("layers");
if (oldApi.isLayersFirstIsBaseLayer()) {
for (int i = oldLayers.size() - 1; i > -1; i--) {
PJsonObject oldLayer = (PJsonObject) oldLayers.getObject(i);
layers.put(OldAPILayerConverter.convert(oldLayer, oldApi));
}
} else {
for (int i = 0; i < oldLayers.size(); i++) {
PJsonObject oldLayer = (PJsonObject) oldLayers.getObject(i);
layers.put(OldAPILayerConverter.convert(oldLayer, oldApi));
}
}
}
/**
* Converts the old API legend requestData. "legends": [{ "name": "", "classes": [{ "name": "test",
* "icons": ["http://ref.geoview.bl.ch/print3/wsgi/mapserv_proxy?"] }] }]
*
* to the new API: "legend": { "name": "", "classes": [{ "name": "Arbres", "icons":
* ["http://localhost:9876/e2egeoserver/www/legends/arbres.png"] }, { "name": "Peturbations", "icons":
* ["http://localhost:9876/e2egeoserver/www/legends/perturbations.png"] }, { "name": "Points de vente",
* "icons": ["http://localhost:9876/e2egeoserver/www/legends/points-de-vente.png"] }, { "name":
* "Stationement", "icons": ["http://localhost:9876/e2egeoserver/www/legends/stationement.png"] }] },
*/
private static void setLegendAttribute(
final JSONObject attributes,
final PJsonObject oldRequest,
final Template template) throws JSONException {
final List legendProcessors = getLegendProcessor(template);
PJsonArray oldLegendJson = getLegendJson(oldRequest);
if (legendProcessors.isEmpty()) {
if (oldLegendJson == null) {
// no table, no work
return;
} else {
LOGGER.warn(
"The request json data has attribute information for creating the map but config " +
"does not have a" +
"map attribute. Check that the request and the config.yaml are correct.");
return;
}
} else if (oldLegendJson == null) {
LOGGER.warn("Configuration expects a table, but no table data is defined in the request");
oldLegendJson = new PJsonArray(oldRequest, new JSONArray(), "generated");
}
if (legendProcessors.size() != oldLegendJson.size()) {
LOGGER.warn(
"Not all legends processors have request data. There are " + legendProcessors.size() +
" and there are " + oldLegendJson.size() + " legend request objects.");
}
String legendAttName = "legend";
for (int i = 0; i < legendProcessors.size(); i++) {
LegendProcessor legendProcessor = legendProcessors.get(i);
if (legendProcessor.getInputMapperBiMap().containsValue("legend")) {
legendAttName = legendProcessor.getInputMapperBiMap().inverse().get("legend");
}
final JSONObject value;
if (oldLegendJson.size() > i) {
value = oldLegendJson.getJSONObject(i).getInternalObj();
} else {
value = new JSONObject();
}
attributes.put(legendAttName, value);
}
if (legendProcessors.size() < oldLegendJson.size()) {
JSONObject newApiValue = new JSONObject();
JSONArray classes = new JSONArray();
newApiValue.put("classes", classes);
classes.put(attributes.get(legendAttName));
attributes.put(legendAttName, newApiValue);
for (int i = legendProcessors.size(); i < oldLegendJson.size(); i++) {
classes.put(oldLegendJson.getJSONObject(i).getInternalObj());
}
}
}
private static PJsonArray getLegendJson(final PJsonObject oldRequest) {
return oldRequest.optJSONArray("legends");
}
private static List getLegendProcessor(final Template template) {
List processors = Lists.newArrayList();
for (Processor processor: template.getProcessors()) {
if (processor instanceof LegendProcessor) {
LegendProcessor legendProcessor = (LegendProcessor) processor;
processors.add(legendProcessor);
}
}
return processors;
}
/**
* Converts a table definition from something like:
*
* "table":{ "data":[ { "col0":"a", "col1":"b", "col2":"c" }, { "col0":"d", "col1":"e", "col2":"f" }, {},
* {} ], "columns":[ "col0", "col1", "col2" ] }, "col0":"Column 1", "col1":"Column 2", "col2":"Column 3"
*
* ... to ...:
*
* "table": { "columns": ["Column 1", "Column 2", "Column 3"], "data": [ ["a", "b", "c"], ["d", "e", "f"]
* ] },
*/
private static void setTableAttribute(
final JSONObject attributes,
final PJsonObject oldRequest, final Template template) throws JSONException {
final TableProcessor tableProcessor = getTableProcessor(template);
PJsonObject oldTablePage = (PJsonObject) getOldTablePage(oldRequest);
if (tableProcessor == null) {
if (oldTablePage == null) {
// no table, no work
return;
} else {
LOGGER.warn(
"The request json data has attribute information for creating the map but config " +
"does not have a" +
"map attribute. Check that the request and the config.yaml are correct.");
return;
}
} else if (oldTablePage == null) {
LOGGER.warn("Configuration expects a table, but no table data is defined in the request");
oldTablePage = new PJsonObject(oldRequest, new JSONObject(), "generated");
}
String tableAttributeName = "table";
if (tableProcessor.getInputMapperBiMap().containsValue("table")) {
tableAttributeName = tableProcessor.getInputMapperBiMap().inverse().get("table");
}
final JSONObject table = new JSONObject();
attributes.put(tableAttributeName, table);
final List columnKeys = getTableColumnKeys(oldTablePage);
final List columnLabels = getTableColumnLabels(columnKeys, oldTablePage);
final List tableData = getTableData(columnKeys, oldTablePage);
table.put("columns", columnLabels);
table.put("data", tableData);
}
private static TableProcessor getTableProcessor(final Template template) {
TableProcessor tableProcessor = null;
for (Processor, ?> processor: template.getProcessors()) {
if (processor instanceof TableProcessor) {
if (tableProcessor == null) {
tableProcessor = (TableProcessor) processor;
} else {
throw new UnsupportedOperationException("Template contains "
+
"more than one table configuration. The" +
" legacy API "
+
"supports only one table per template.");
}
}
}
return tableProcessor;
}
private static PObject getOldTablePage(final PJsonObject oldRequest) {
final PArray pages = oldRequest.getArray("pages");
PObject tablePage = null;
for (int i = 0; i < pages.size(); i++) {
final PObject page = pages.getObject(i);
if (isTablePage(page)) {
if (tablePage == null) {
tablePage = page;
} else {
throw new UnsupportedOperationException("Request contains "
+
"more than one page with a table. The " +
"legacy API "
+ "supports only one table per report.");
}
}
}
return tablePage;
}
private static boolean isTablePage(final PObject page) {
if (page.has("table")) {
// page has a table, but let's check if it's not a "dummy" table created by GeoExt,
// like this one:
//
// "table":{
// "data":[
// {
// "col0":""
// }
// ],
// "columns":[
// "col0"
// ]
// }
PObject table = page.getObject("table");
if (table.getArray("columns").size() == 1 && table.getArray("data").size() == 1) {
String columnName = table.getArray("columns").getString(0);
String value = table.getArray("data").getObject(0).getString(columnName);
return !Strings.isNullOrEmpty(value);
}
return true;
}
return false;
}
private static List getTableColumnKeys(final PJsonObject oldTablePage) {
final PJsonObject table = oldTablePage.optJSONObject("table");
final List columnKeys = new LinkedList<>();
if (table != null) {
final PArray columns =
table.optArray("columns", new PJsonArray(table, new JSONArray(), "columns"));
for (int i = 0; i < columns.size(); i++) {
columnKeys.add(columns.getString(i));
}
}
return columnKeys;
}
private static List getTableColumnLabels(
final List columnKeys,
final PJsonObject oldTablePage) {
final List columnLabels = new LinkedList<>();
for (String key: columnKeys) {
if (oldTablePage.has(key)) {
columnLabels.add(oldTablePage.getString(key));
} else {
columnLabels.add("");
}
}
return columnLabels;
}
private static List getTableData(
final List columnKeys,
final PJsonObject oldTablePage) {
final PJsonObject table = oldTablePage.optJSONObject("table");
final List tableData = new LinkedList<>();
if (table != null) {
final PArray oldTableRows =
table.optArray("data", new PJsonArray(table, new JSONArray(), "data"));
for (int i = 0; i < oldTableRows.size(); i++) {
final PObject oldRow = oldTableRows.getObject(i);
if (!oldRow.keys().hasNext()) {
// row is empty, skip
continue;
}
// copy the values for each column
final JSONArray row = new JSONArray();
for (String key: columnKeys) {
row.put(oldRow.getString(key));
}
tableData.add(row);
}
}
return tableData;
}
}