org.mapfish.print.servlet.oldapi.OldAPIMapPrinterServlet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of print-lib Show documentation
Show all versions of print-lib Show documentation
Library for generating PDFs and images from online webmapping services
package org.mapfish.print.servlet.oldapi;
import com.google.common.base.Strings;
import org.json.JSONException;
import org.json.JSONWriter;
import org.mapfish.print.Constants;
import org.mapfish.print.ExceptionUtils;
import org.mapfish.print.MapPrinter;
import org.mapfish.print.MapPrinterFactory;
import org.mapfish.print.attribute.Attribute;
import org.mapfish.print.attribute.map.MapAttribute;
import org.mapfish.print.attribute.map.MapAttribute.MapAttributeValues;
import org.mapfish.print.attribute.map.ZoomLevels;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.config.Template;
import org.mapfish.print.map.DistanceUnit;
import org.mapfish.print.map.Scale;
import org.mapfish.print.servlet.BaseMapServlet;
import org.mapfish.print.servlet.MapPrinterServlet;
import org.mapfish.print.servlet.NoSuchAppException;
import org.mapfish.print.servlet.job.JobManager;
import org.mapfish.print.servlet.job.NoSuchReferenceException;
import org.mapfish.print.wrapper.json.PJsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.DecimalFormat;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.mapfish.print.Constants.PDF_DPI;
import static org.mapfish.print.servlet.ServletMapPrinterFactory.DEFAULT_CONFIGURATION_FILE_KEY;
/**
* Servlet with the old print API.
*/
@Controller
public class OldAPIMapPrinterServlet extends BaseMapServlet {
static final String REPORT_SUFFIX = ".printout";
static final String JSON_PRINT_URL = "printURL";
static final String JSON_CREATE_URL = "createURL";
private static final Logger LOGGER = LoggerFactory.getLogger(OldAPIMapPrinterServlet.class);
private static final String DEP_SEG = "/dep";
private static final String INFO_URL = "/info.json";
private static final String DEP_INFO_URL = DEP_SEG + INFO_URL;
private static final String PRINT_URL = "/print.pdf";
private static final String DEP_PRINT_URL = DEP_SEG + PRINT_URL;
private static final String CREATE_URL = "/create.json";
private static final String DEP_CREATE_URL = DEP_SEG + CREATE_URL;
private static final int HALF_SECOND = 500;
@Autowired
private MapPrinterFactory printerFactory;
@Autowired
private MapPrinterServlet primaryApiServlet;
@Autowired
private JobManager jobManager;
/**
* Print the report from a POST request.
*
* @param requestData the request spec as POST body
* @param httpServletRequest the request object
* @param httpServletResponse the response object
*/
@RequestMapping(value = DEP_PRINT_URL, method = RequestMethod.POST)
public final void printReportPost(
@RequestBody final String requestData,
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse) {
if (Strings.isNullOrEmpty(requestData)) {
error(httpServletResponse, "Missing 'spec' parameter", HttpStatus.INTERNAL_SERVER_ERROR);
return;
}
createAndGetPDF(httpServletRequest, httpServletResponse, requestData);
}
/**
* Print the report from a GET request. Avoid to use it, the accents in the spec are not all supported.
*
* @param spec the request spec as GET parameter
* @param httpServletRequest the request object
* @param httpServletResponse the response object
*/
@RequestMapping(value = DEP_PRINT_URL, method = RequestMethod.GET)
public final void printReport(
@RequestParam(value = "spec", defaultValue = "") final String spec,
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse) {
if (Strings.isNullOrEmpty(spec)) {
error(httpServletResponse, "Missing 'spec' parameter", HttpStatus.INTERNAL_SERVER_ERROR);
return;
}
createAndGetPDF(httpServletRequest, httpServletResponse, spec);
}
/**
* Create the report from a POST request.
*
* @param baseUrl the base url to the servlet
* @param spec if spec is form data then this will be nonnull
* @param requestData the request spec as POST body
* @param httpServletRequest the request object
* @param httpServletResponse the response object
*/
@RequestMapping(value = DEP_CREATE_URL + "**", method = RequestMethod.POST)
public final void createReportPost(
@RequestParam(value = "url", defaultValue = "") final String baseUrl,
@RequestParam(value = "spec", required = false) final String spec,
@RequestBody final String requestData,
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse) throws IOException, JSONException {
if (Strings.isNullOrEmpty(requestData)) {
// TODO in case the POST body is empty, status code 415 is returned automatically, so we never
// get here
error(httpServletResponse, "Missing 'spec' parameter", HttpStatus.INTERNAL_SERVER_ERROR);
return;
}
String baseUrlPath = getBaseUrl(DEP_CREATE_URL,
URLDecoder.decode(baseUrl, Constants.DEFAULT_ENCODING),
httpServletRequest);
String specData = spec == null ? requestData : spec;
createPDF(httpServletRequest, httpServletResponse, baseUrlPath, specData);
}
/**
* All in one method: create and returns the PDF to the client.
*
* @param httpServletRequest the request object
* @param httpServletResponse the response object
* @param spec the request spec
*/
private void createAndGetPDF(
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse, final String spec) {
try {
httpServletRequest.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {
throw ExceptionUtils.getRuntimeException(e);
}
try {
String jobRef = doCreatePDFFile(spec, httpServletRequest, httpServletResponse);
this.primaryApiServlet.getReport(jobRef, false, httpServletResponse);
} catch (NoSuchAppException e) {
error(httpServletResponse, e.getMessage(), HttpStatus.NOT_FOUND);
} catch (Throwable e) {
error(httpServletResponse, e);
}
}
/**
* Create the PDF and returns to the client (in JSON) the URL to get the PDF.
*
* @param httpServletRequest the request object
* @param httpServletResponse the response object
* @param basePath the path of the webapp
* @param spec the request spec
*/
protected final void createPDF(
final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse,
final String basePath, final String spec) throws JSONException {
String jobRef;
try {
try {
jobRef = doCreatePDFFile(spec, httpServletRequest, httpServletResponse);
httpServletResponse.setContentType("application/json; charset=utf-8");
try (PrintWriter writer = httpServletResponse.getWriter()) {
JSONWriter json = new JSONWriter(writer);
json.object();
{
json.key("getURL").value(basePath + "/" + jobRef + REPORT_SUFFIX);
}
json.endObject();
}
} catch (NoSuchAppException e) {
error(httpServletResponse, e.getMessage(), HttpStatus.NOT_FOUND);
return;
}
} catch (Throwable e) {
error(httpServletResponse, e);
return;
}
}
/**
* To get the PDF created previously and write it to the http response.
*
* @param inline if true then inline the response
* @param response the http response
* @param id the id for the file
*/
@RequestMapping(DEP_SEG + "/{id:.+}" + REPORT_SUFFIX)
public final void getFile(
@PathVariable final String id,
@RequestParam(value = "inline", defaultValue = "false") final boolean inline,
final HttpServletResponse response)
throws IOException, ServletException {
this.primaryApiServlet.getReport(id, inline, response);
}
/**
* To get (in JSON) the information about the available formats and CO.
*
* @param baseUrl the path to the webapp
* @param jsonpVar if given the result is returned as a variable assignment
* @param req the http request
* @param appId the app request
* @param resp the http response
*/
@RequestMapping(DEP_INFO_URL)
public final void getInfo(
@RequestParam(value = "url", defaultValue = "") final String baseUrl,
@RequestParam(value = "var", defaultValue = "") final String jsonpVar,
@RequestParam(value = "app", defaultValue = DEFAULT_CONFIGURATION_FILE_KEY) final String appId,
final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
final MapPrinter printer;
try {
printer = this.printerFactory.create(appId);
} catch (NoSuchAppException e) {
error(resp, e.getMessage(), HttpStatus.NOT_FOUND);
return;
}
resp.setContentType("application/json; charset=utf-8");
final PrintWriter writer = resp.getWriter();
try {
if (!Strings.isNullOrEmpty(jsonpVar)) {
writer.print("var " + jsonpVar + "=");
}
JSONWriter json = new JSONWriter(writer);
try {
json.object();
writeInfoJson(json, baseUrl, printer, req);
json.endObject();
} catch (JSONException e) {
throw new ServletException(e);
}
if (!Strings.isNullOrEmpty(jsonpVar)) {
writer.print(";");
}
} catch (UnsupportedOperationException exc) {
error(resp, exc.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
throw new ServletException(exc);
} catch (Exception exc) {
error(resp, "Unexpected error, please see the server logs", HttpStatus.INTERNAL_SERVER_ERROR);
throw new ServletException(exc);
} finally {
writer.close();
}
}
private void writeInfoJson(
final JSONWriter json, final String baseUrl,
final MapPrinter printer, final HttpServletRequest req)
throws JSONException {
json.key("outputFormats");
json.array();
{
for (String format: printer.getOutputFormatsNames()) {
json.object();
json.key("name").value(format);
json.endObject();
}
}
json.endArray();
writeInfoLayouts(json, printer.getConfiguration());
String urlToUseInSpec = getBaseUrl(DEP_INFO_URL, baseUrl, req);
json.key(JSON_PRINT_URL).value(urlToUseInSpec + PRINT_URL);
json.key(JSON_CREATE_URL).value(urlToUseInSpec + CREATE_URL);
}
private void writeInfoLayouts(final JSONWriter json, final Configuration configuration)
throws JSONException {
Double maxDpi = null;
double[] dpiSuggestions = null;
ZoomLevels zoomLevels = null;
json.key("layouts");
json.array();
for (String name: configuration.getTemplates().keySet()) {
json.object();
{
json.key("name").value(name);
json.key("rotation").value(true);
Template template = configuration.getTemplates().get(name);
// find the map attribute
MapAttribute map = null;
for (Attribute attribute: template.getAttributes().values()) {
if (attribute instanceof MapAttribute) {
if (map != null) {
throw new UnsupportedOperationException(String.format(
"Template '%s' contains more than one map configuration. " +
"The legacy API supports only one map per template.", name));
} else {
map = (MapAttribute) attribute;
}
}
}
if (map == null) {
LOGGER.warn(String.format("Template '%s' contains no map configuration.", name));
} else {
MapAttributeValues mapValues = map.createValue(template);
json.key("map");
json.object();
{
json.key("width").value(mapValues.getMapSize().width);
json.key("height").value(mapValues.getMapSize().height);
}
json.endObject();
// get the zoom levels and dpi values from the first template
if (maxDpi == null) {
maxDpi = map.getMaxDpi();
dpiSuggestions = map.getDpiSuggestions();
}
if (zoomLevels == null) {
zoomLevels = mapValues.getZoomLevels();
}
}
}
json.endObject();
}
json.endArray();
json.key("dpis");
json.array();
{
if (dpiSuggestions != null) {
for (Double dpi: dpiSuggestions) {
json.object();
{
json.key("name").value(Integer.toString(dpi.intValue()));
json.key("value").value(Integer.toString(dpi.intValue()));
}
json.endObject();
}
}
}
json.endArray();
json.key("scales");
json.array();
{
if (zoomLevels != null) {
{
for (int i = 0; i < zoomLevels.size(); i++) {
Scale scale = zoomLevels.get(i, DistanceUnit.M);
json.object();
{
String scaleValue = new DecimalFormat("#.##").format(
scale.getDenominator(PDF_DPI));
json.key("name").value("1:" + scaleValue);
json.key("value").value(scaleValue);
}
json.endObject();
}
}
}
}
json.endArray();
}
private String getBaseUrl(final String suffix, final String baseUrl, final HttpServletRequest req) {
String urlToUseInSpec;
if (!Strings.isNullOrEmpty(baseUrl) && baseUrl.endsWith(suffix)) {
urlToUseInSpec = baseUrl.replace(suffix, DEP_SEG);
} else if (!Strings.isNullOrEmpty(baseUrl)) {
urlToUseInSpec = removeLastSlash(baseUrl);
} else {
urlToUseInSpec = removeLastSlash(super.getBaseUrl(req).toString()) + DEP_SEG;
}
urlToUseInSpec = removeLastSlash(urlToUseInSpec);
return urlToUseInSpec;
}
private String removeLastSlash(final String urlToUseInSpec) {
if (urlToUseInSpec.endsWith("/")) {
return urlToUseInSpec.substring(1);
}
return urlToUseInSpec;
}
/**
* Do the actual work of creating the PDF temporary file.
*
* @param spec the json specification in the old API format
* @param httpServletRequest the request
*/
private String doCreatePDFFile(
final String spec,
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse)
throws
InterruptedException, NoSuchAppException, NoSuchReferenceException {
LOGGER.debug("\nOLD-API:\n{}", spec);
PJsonObject specJson = MapPrinterServlet.parseJson(spec, httpServletResponse);
String appId;
if (specJson.has("app")) {
appId = specJson.getString("app");
} else {
appId = DEFAULT_CONFIGURATION_FILE_KEY;
}
MapPrinter mapPrinter = this.printerFactory.create(appId);
PJsonObject updatedSpecJson = null;
try {
updatedSpecJson = OldAPIRequestConverter.convert(specJson, mapPrinter.getConfiguration());
String format = updatedSpecJson.optString(MapPrinterServlet.JSON_OUTPUT_FORMAT, "pdf");
final String jobReferenceId = this.primaryApiServlet.createAndSubmitPrintJob(
appId, format, updatedSpecJson.getInternalObj().toString(), httpServletRequest,
httpServletResponse);
boolean isDone = false;
while (!isDone) {
Thread.sleep(HALF_SECOND);
isDone = this.jobManager.getStatus(jobReferenceId).isDone();
}
return jobReferenceId;
} catch (JSONException e) {
throw ExceptionUtils.getRuntimeException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy