All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mapfish.print.config.Configuration Maven / Gradle / Ivy

There is a newer version: 3.22.0
Show newest version
package org.mapfish.print.config;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.Mark;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.Symbolizer;
import org.json.JSONException;
import org.json.JSONWriter;
import org.mapfish.print.Constants;
import org.mapfish.print.config.access.AccessAssertion;
import org.mapfish.print.config.access.AlwaysAllowAssertion;
import org.mapfish.print.config.access.RoleAccessAssertion;
import org.mapfish.print.http.CertificateStore;
import org.mapfish.print.http.HttpCredential;
import org.mapfish.print.http.HttpProxy;
import org.mapfish.print.map.style.StyleParser;
import org.mapfish.print.map.style.json.ColorParser;
import org.mapfish.print.processor.http.matcher.URIMatcher;
import org.mapfish.print.processor.http.matcher.UriMatchers;
import org.mapfish.print.servlet.fileloader.ConfigFileLoaderManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;

import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;


/**
 * The Main Configuration Bean.
 * 

*/ public class Configuration implements ConfigurationObject { private static final Map GEOMETRY_NAME_ALIASES; static { HashMap map = new HashMap<>(); map.put(Geometry.class.getSimpleName().toLowerCase(), Geometry.class.getSimpleName().toLowerCase()); map.put("geom", Geometry.class.getSimpleName().toLowerCase()); map.put("geometrycollection", Geometry.class.getSimpleName().toLowerCase()); map.put("multigeometry", Geometry.class.getSimpleName().toLowerCase()); map.put("line", LineString.class.getSimpleName().toLowerCase()); map.put(LineString.class.getSimpleName().toLowerCase(), LineString.class.getSimpleName().toLowerCase()); map.put("linearring", LineString.class.getSimpleName().toLowerCase()); map.put("multilinestring", LineString.class.getSimpleName().toLowerCase()); map.put("multiline", LineString.class.getSimpleName().toLowerCase()); map.put("poly", Polygon.class.getSimpleName().toLowerCase()); map.put(Polygon.class.getSimpleName().toLowerCase(), Polygon.class.getSimpleName().toLowerCase()); map.put("multipolygon", Polygon.class.getSimpleName().toLowerCase()); map.put(Point.class.getSimpleName().toLowerCase(), Point.class.getSimpleName().toLowerCase()); map.put("multipoint", Point.class.getSimpleName().toLowerCase()); map.put(Constants.Style.OverviewMap.NAME, Constants.Style.OverviewMap.NAME); GEOMETRY_NAME_ALIASES = map; } private Map templates; private File configurationFile; private Map styles = new HashMap<>(); private Map defaultStyle = new HashMap<>(); private boolean throwErrorOnExtraParameters = true; private List proxies = Lists.newArrayList(); private PDFConfig pdfConfig = new PDFConfig(); private List credentials = Lists.newArrayList(); private CertificateStore certificateStore; private OldApiConfig oldApi = new OldApiConfig(); private String outputFilename; private String resourceBundle; private boolean defaultToSvg = false; private Set jdbcDrivers = Sets.newHashSet(); private Map namedStyles = Maps.newHashMap(); private UriMatchers allowedReferers = null; /** * The color used to draw the WMS tiles error default: transparent pink. */ private String transparentTileErrorColor = "rgba(255, 78, 78, 125)"; /** * The color used to draw the other tiles error default: pink. */ private String opaqueTileErrorColor = "rgba(255, 155, 155, 0)"; @Autowired private StyleParser styleParser; @Autowired private ClientHttpRequestFactory clientHttpRequestFactory; @Autowired private ConfigFileLoaderManager fileLoaderManager; @Autowired private ApplicationContext context; private AccessAssertion accessAssertion = AlwaysAllowAssertion.INSTANCE; final PDFConfig getPdfConfig() { return this.pdfConfig; } /** * Configure various properties related to the reports generated as PDFs. * * @param pdfConfig the pdf configuration */ public final void setPdfConfig(final PDFConfig pdfConfig) { this.pdfConfig = pdfConfig; } /** * Initialize some optionally wired fields. */ @PostConstruct public final void init() { this.namedStyles = this.context.getBeansOfType(Style.class); } /** * Either use the provided value (renderAsSvg) or if it is null then use {@link #defaultToSvg}. * * @param renderAsSvg the value to use if non-null. */ public final boolean renderAsSvg(final Boolean renderAsSvg) { return renderAsSvg == null ? this.defaultToSvg : renderAsSvg; } /** * If true then all vector layers (and other parts of the system that can be either SVG or Bitmap, like * scalebar) will be rendered as SVG (unless layer specifically indicates useSvg as false). *

* The default is false. *

* * @param defaultToSvg whether or not to create svg layers by default */ public final void setDefaultToSvg(final boolean defaultToSvg) { this.defaultToSvg = defaultToSvg; } /** * The configuration for locating a custom certificate store. */ @Nullable public final CertificateStore getCertificateStore() { return this.certificateStore; } /** * The configuration for locating a custom certificate store. This is only required if the default * certificate store which ships with all java installations does not contain the certificates needed by * this server. Usually it is to accept a self-signed certificate, for example on a test server. * * @param certificateStore The configuration for locating a custom certificate store */ public final void setCertificateStore(final CertificateStore certificateStore) { this.certificateStore = certificateStore; } /** * Get the http credentials. Should also getProxies since {@link org.mapfish.print.http.HttpProxy} is a * subclass of {@link org.mapfish.print.http.HttpCredential}. */ public final List getCredentials() { return this.credentials; } /** * Http credentials to be used when making http requests. *

* If a proxy needs credentials you don't need to configure it here because the proxy configuration object * also has options for declaring the credentials. *

* * @param credentials the credentials */ public final void setCredentials(final List credentials) { this.credentials = credentials; } /** * Get the http proxies used by in all requests in this syste. * * @see org.mapfish.print.http.ConfigFileResolvingHttpRequestFactory */ public final List getProxies() { return this.proxies; } /** * Configuration for proxying http requests. Each proxy can be configured with authentication and with * the uris that they apply to. *

* See {@link org.mapfish.print.http.HttpProxy} for details on how to configure them. * * @param proxies the proxy configuration objects */ public final void setProxies(final List proxies) { this.proxies = proxies; } /** * Print out the configuration that the client needs to make a request. * * @param json the output writer. * @throws JSONException */ public final void printClientConfig(final JSONWriter json) throws JSONException { json.key("layouts"); json.array(); final Map accessibleTemplates = getTemplates(); for (String name: accessibleTemplates.keySet()) { json.object(); json.key("name").value(name); accessibleTemplates.get(name).printClientConfig(json); json.endObject(); } json.endArray(); } public final String getOutputFilename() { return this.outputFilename; } /** * The default output file name of the report. This can be overridden by {@link * org.mapfish.print.config.Template#setOutputFilename(String)} and the outputFilename parameter in the * request JSON. *

* This can be a string and can also have a date section in the string that will be filled when the report * is created for example a section with ${<dateFormatString>} will be replaced with the current * date formatted in the way defined by the <dateFormatString> string. The format rules are the * rules in * * java.text.SimpleDateFormat (do a google search if the link above is broken). *

*

* Example: outputFilename: print-${dd-MM-yyyy} should output: * print-22-11-2014.pdf *

*

* Note: the suffix will be appended to the end of the name. *

* * @param outputFilename default output file name of the report. */ public final void setOutputFilename(final String outputFilename) { this.outputFilename = outputFilename; } public final Map getTemplates() { return Maps.filterEntries(this.templates, new Predicate>() { @Override public boolean apply(@Nullable final Map.Entry input) { if (input == null) { return false; } try { Configuration.this.accessAssertion.assertAccess("Configuration", this); input.getValue().assertAccessible(input.getKey()); return true; } catch (AccessDeniedException | AuthenticationCredentialsNotFoundException e) { return false; } } }); } /** * Set the configuration of the named template. * * @param templates the templates; */ public final void setTemplates(final Map templates) { this.templates = templates; } /** * Retrieve the configuration of the named template. * * @param name the template name; */ public final Template getTemplate(final String name) { final Template template = this.templates.get(name); if (template != null) { this.accessAssertion.assertAccess("Configuration", this); template.assertAccessible(name); } else { throw new IllegalArgumentException(String.format("Template '%s' does not exist. Options are: " + "%s", name, this.templates.keySet())); } return template; } public final File getDirectory() { return this.configurationFile.getAbsoluteFile().getParentFile(); } public final void setConfigurationFile(final File configurationFile) { this.configurationFile = configurationFile; } /** * Set the named styles defined in the configuration for this. * * @param styles the style definition. StyleParser plugins will be used to load the style. */ public final void setStyles(final Map styles) { this.styles = styles; } /** * Return the named style ot Optional.absent() if there is not a style with the given name. * * @param styleName the name of the style to look up */ public final Optional getStyle(final String styleName) { final String styleRef = this.styles.get(styleName); if (styleRef != null) { return this.styleParser.loadStyle(this, this.clientHttpRequestFactory, styleRef); } else { return Optional.absent(); } } /** * Get a default style. If null a simple black line style will be returned. * * @param geometryType the name of the geometry type (point, line, polygon) */ @Nonnull public final Style getDefaultStyle(@Nonnull final String geometryType) { String normalizedGeomName = GEOMETRY_NAME_ALIASES.get(geometryType.toLowerCase()); if (normalizedGeomName == null) { normalizedGeomName = geometryType.toLowerCase(); } Style style = this.defaultStyle.get(normalizedGeomName.toLowerCase()); if (style == null) { style = this.namedStyles.get(normalizedGeomName.toLowerCase()); } if (style == null) { StyleBuilder builder = new StyleBuilder(); final Symbolizer symbolizer; if (isPointType(normalizedGeomName)) { symbolizer = builder.createPointSymbolizer(); } else if (isLineType(normalizedGeomName)) { symbolizer = builder.createLineSymbolizer(Color.black, 2); } else if (isPolygonType(normalizedGeomName)) { symbolizer = builder.createPolygonSymbolizer(Color.lightGray, Color.black, 2); } else if (normalizedGeomName.equalsIgnoreCase(Constants.Style.Raster.NAME)) { symbolizer = builder.createRasterSymbolizer(); } else if (normalizedGeomName.startsWith(Constants.Style.OverviewMap.NAME)) { symbolizer = createMapOverviewStyle(normalizedGeomName, builder); } else { final Style geomStyle = this.defaultStyle.get(Geometry.class.getSimpleName().toLowerCase()); if (geomStyle != null) { return geomStyle; } else { symbolizer = builder.createPointSymbolizer(); } } style = builder.createStyle(symbolizer); } return style; } private boolean isPolygonType(@Nonnull final String normalizedGeomName) { return normalizedGeomName.equalsIgnoreCase(Polygon.class.getSimpleName()) || normalizedGeomName.equalsIgnoreCase(MultiPolygon.class.getSimpleName()); } private boolean isLineType(@Nonnull final String normalizedGeomName) { return normalizedGeomName.equalsIgnoreCase(LineString.class.getSimpleName()) || normalizedGeomName.equalsIgnoreCase(MultiLineString.class.getSimpleName()) || normalizedGeomName.equalsIgnoreCase(LinearRing.class.getSimpleName()); } private boolean isPointType(@Nonnull final String normalizedGeomName) { return normalizedGeomName.equalsIgnoreCase(Point.class.getSimpleName()) || normalizedGeomName.equalsIgnoreCase(MultiPoint.class.getSimpleName()); } private Symbolizer createMapOverviewStyle( @Nonnull final String normalizedGeomName, @Nonnull final StyleBuilder builder) { Stroke stroke = builder.createStroke(Color.blue, 2); final Fill fill = builder.createFill(Color.blue, 0.2); String overviewGeomType = Polygon.class.getSimpleName(); if (normalizedGeomName.contains(":")) { final String[] parts = normalizedGeomName.split(":"); overviewGeomType = parts[1]; } if (isPointType(overviewGeomType)) { final Mark mark = builder.createMark(StyleBuilder.MARK_CIRCLE, fill, stroke); Graphic graphic = builder.createGraphic(null, mark, null); graphic.setSize(builder.literalExpression(Constants.Style.POINT_SIZE)); return builder.createPointSymbolizer(graphic); } if (isLineType(overviewGeomType)) { return builder.createLineSymbolizer(stroke); } return builder.createPolygonSymbolizer(stroke, fill); } /** * Set the default styles. the case of the keys are not important. The retrieval will be case * insensitive. * * @param defaultStyle the mapping from geometry type name (point, polygon, etc...) to the style * to use for that type. */ public final void setDefaultStyle(final Map defaultStyle) { this.defaultStyle = Maps.newHashMapWithExpectedSize(defaultStyle.size()); for (Map.Entry entry: defaultStyle.entrySet()) { String normalizedName = GEOMETRY_NAME_ALIASES.get(entry.getKey().toLowerCase()); if (normalizedName == null) { normalizedName = entry.getKey().toLowerCase(); } this.defaultStyle.put(normalizedName, entry.getValue()); } } /** * If true and the request JSON has extra parameters in the layers definition, exceptions will be thrown. * Otherwise the information will be logged. */ public final boolean isThrowErrorOnExtraParameters() { return this.throwErrorOnExtraParameters; } /** * If true and the request JSON has extra parameters in the layers definition, exceptions will be thrown. * Otherwise the information will be logged. * * @param throwErrorOnExtraParameters the value */ public final void setThrowErrorOnExtraParameters(final boolean throwErrorOnExtraParameters) { this.throwErrorOnExtraParameters = throwErrorOnExtraParameters; } @Override public void validate(final List validationErrors, final Configuration configuration) { validationErrors.addAll(validate()); } /** * Validate that the configuration is valid. * * @return any validation errors. */ public final List validate() { List validationErrors = Lists.newArrayList(); this.accessAssertion.validate(validationErrors, this); for (String jdbcDriver: this.jdbcDrivers) { try { Class.forName(jdbcDriver); } catch (ClassNotFoundException e) { try { Configuration.class.getClassLoader().loadClass(jdbcDriver); } catch (ClassNotFoundException e1) { validationErrors.add(new ConfigurationException(String.format( "Unable to load JDBC driver: %s ensure that the web application has the jar " + "on its classpath", jdbcDriver))); } } } if (this.configurationFile == null) { validationErrors.add(new ConfigurationException("Configuration file is field on configuration " + "object is null")); } if (this.templates.isEmpty()) { validationErrors.add(new ConfigurationException("There are not templates defined.")); } for (Template template: this.templates.values()) { template.validate(validationErrors, this); } for (HttpProxy proxy: this.proxies) { proxy.validate(validationErrors, this); } try { ColorParser.toColor(this.opaqueTileErrorColor); } catch (RuntimeException ex) { validationErrors.add(new ConfigurationException("Cannot parse opaqueTileErrorColor", ex)); } try { ColorParser.toColor(this.transparentTileErrorColor); } catch (RuntimeException ex) { validationErrors.add(new ConfigurationException("Cannot parse transparentTileErrorColor", ex)); } return validationErrors; } /** * check if the file exists and can be accessed by the user/template/config/etc... * * @param pathToSubResource a string representing a file that is accessible for use in printing * templates within the configuration file. In the case of a file based URI the path could be a * relative path (relative to the configuration file) or an absolute path, but it must be an * allowed file (you can't allow access to any file on the file system). */ public final boolean isAccessible(final String pathToSubResource) throws IOException { return this.fileLoaderManager.isAccessible(this.configurationFile.toURI(), pathToSubResource); } /** * Load the file related to the configuration file. * * @param pathToSubResource a string representing a file that is accessible for use in printing * templates within the configuration file. In the case of a file based URI the path could be a * relative path (relative to the configuration file) or an absolute path, but it must be an * allowed file (you can't allow access to any file on the file system). */ public final byte[] loadFile(final String pathToSubResource) throws IOException { return this.fileLoaderManager.loadFile(this.configurationFile.toURI(), pathToSubResource); } /** * Set file loader manager. * * @param fileLoaderManager new manager. */ public final void setFileLoaderManager(final ConfigFileLoaderManager fileLoaderManager) { this.fileLoaderManager = fileLoaderManager; } /** * Set the JDBC drivers that are required to connect to the databases in the configuration. JDBC drivers * are needed (for example) when database sources are used in templates. For example if in one of the * template you have: * *

     *     jdbcUrl: "jdbc:postgresql://localhost:5432/morges_dpfe"
     * 
*

* then you need to add: * *


     *     jdbcDrivers: [org.postgresql.Driver]
     * 
     * 
*

* or * *


     *     jdbcDrivers:
     *       - org.postgresql.Driver
     * 
* * @param jdbcDrivers the set of JDBC drivers to load before performing a print (this ensures they * are registered with the JVM) */ public final void setJdbcDrivers(final Set jdbcDrivers) { this.jdbcDrivers = jdbcDrivers; } /** * The roles required to access this configuration/app. If empty or not set then it is a * public app. If there are many roles then a user must have one of the roles in order to * access the configuration/app. *

* The security (how authentication/authorization is done) is configured in the * /WEB-INF/classes/mapfish-spring-security.xml *

* Any user without the required role will get an error when trying to access any of the templates and no * templates will be listed in the capabilities requests. *

* * @param access the roles needed to access this */ public final void setAccess(final ArrayList access) { final RoleAccessAssertion assertion = new RoleAccessAssertion(); assertion.setRequiredRoles(access); this.accessAssertion = assertion; } public final AccessAssertion getAccessAssertion() { return this.accessAssertion; } /** * Get the configuration options on how to interpret the request in the form of the old API. */ public final OldApiConfig getOldApi() { return this.oldApi; } /** * Set the configuration options on how to interpret the request in the form of the old API. * * @param oldApi the old api configuration object */ public final void setOldApi(final OldApiConfig oldApi) { this.oldApi = oldApi; } /** * Get the color used to draw the WMS tiles error default: transparent pink. */ public final String getTransparentTileErrorColor() { return this.transparentTileErrorColor; } /** * Color used for tiles in error on transparent layers. * * @param transparentTileErrorColor The color */ public final void setTransparentTileErrorColor(final String transparentTileErrorColor) { this.transparentTileErrorColor = transparentTileErrorColor; } /** * Get the color used to draw the other tiles error default: pink. */ public final String getOpaqueTileErrorColor() { return this.opaqueTileErrorColor; } /** * Color used for tiles in error on opaque layers. * * @param opaqueTileErrorColor The color */ public final void setOpaqueTileErrorColor(final String opaqueTileErrorColor) { this.opaqueTileErrorColor = opaqueTileErrorColor; } /** * Get the resource bundle name. */ public final String getResourceBundle() { return this.resourceBundle; } /** * Set the resource bundle name. * * @param resourceBundle the resource bundle name */ public final void setResourceBundle(final String resourceBundle) { this.resourceBundle = resourceBundle; } /** * @return the list of referer checks (null = no check) */ public final UriMatchers getAllowedReferersImpl() { return this.allowedReferers; } /** * The matchers used to authorize the incoming requests in function of the referer. For example: *

     * allowedReferers:
     *   - !hostnameMatch
     *     host: example.com
     *     allowSubDomains: true
     * 
*

* By default, the referer is not checked * * @param matchers the list of matcher to use to check if a referer is permitted or null for no * check * @see org.mapfish.print.processor.http.matcher.URIMatcher */ public final void setAllowedReferers(@Nullable final List matchers) { this.allowedReferers = matchers != null ? new UriMatchers(matchers) : null; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy