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

org.mapfish.print.MapPrinter Maven / Gradle / Ivy

/*
 * Copyright (C) 2013  Camptocamp
 *
 * This file is part of MapFish Print
 *
 * MapFish Print is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MapFish Print 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 General Public License
 * along with MapFish Print.  If not, see .
 */

package org.mapfish.print;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.pdf.ByteBuffer;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.mapfish.print.config.Config;
import org.mapfish.print.config.ConfigFactory;
import org.mapfish.print.output.OutputFactory;
import org.mapfish.print.output.OutputFormat;
import org.mapfish.print.output.PrintParams;
import org.mapfish.print.utils.PJsonObject;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;

/**
 * The main class for printing maps. Will parse the spec, create the PDF
 * document and generate it.
 *
 * This class should not be directly created but rather obtained from an application
 * context object so that all plugins and dependencies are correctly injected into it
 */
public class MapPrinter {
    private static final Logger LOGGER = Logger.getLogger(MapPrinter.class);
    /**
     * The parsed configuration file.
     *
     * This is a per instance property and while can be set by spring typically will be set by user of printer
     */
    private Config config;

    /**
     * The directory where the configuration file sits (used for ${configDir})
     *
     * This is a per instance property and while can be set by spring typically will be set by user of printer
     */
    private File configDir;

    /**
     * OutputFactory for the final output
     *
     * Injected by Spring
     */
    @Autowired
    private OutputFactory outputFactory;
    /**
     * Factory for creating config objects
     *
     * Injected by Spring
     */
    @Autowired
    private ConfigFactory configFactory;

    @Autowired
    private MetricRegistry metricRegistry;

    private volatile boolean fontsInitialized = false;
    
    private int usages = 0;

    static {
        //configure iText to use a higher precision for floats
        ByteBuffer.HIGH_PRECISION = true;
    }
    /**
     * Sets both the configuration by parsing the configFile and the configDir relative to the configFile
     * @param configFile
     * @throws FileNotFoundException
     * @return this
     */
    public MapPrinter setYamlConfigFile(File configFile) throws FileNotFoundException {
        this.config = configFactory.fromYaml(configFile);
        configDir = configFile.getParentFile();
        if (configDir == null) {
            try {
                configDir = new File(".").getCanonicalFile();
            } catch (IOException e) {
                configDir = new File(".");
            }
        }
        return this;
    }

    public MapPrinter setConfig(String strConfig) {
        this.config = configFactory.fromString(strConfig);
        return this;
    }

    public MapPrinter setConfig(InputStream inputConfig) {
        this.config =  configFactory.fromInputStream(inputConfig);
        return this;
    }

    public MapPrinter setConfigDir(String configDir) {
        this.configDir = new File(configDir);
        return this;
    }

    /**
     * Register the user specified fonts in iText.
     */
    private void initFonts() {
        if(!fontsInitialized) {
            synchronized (this) {
                if(!fontsInitialized) {
                    //we don't do that since it takes ages and that would hurt the perfs for
                    //the python controller:
                    //FontFactory.registerDirectories();

                    FontFactory.defaultEmbedding = true;

                    final TreeSet fontPaths = config.getFonts();
                    if (fontPaths != null) {
                        for (String fontPath : fontPaths) {
                            fontPath = fontPath.replaceAll("\\$\\{configDir\\}", configDir.getPath());
                            File fontFile = new File(fontPath);
                            if (fontFile.isDirectory()) {
                                FontFactory.registerDirectory(fontPath, true);
                            } else {
                                FontFactory.register(fontPath);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Generate the PDF using the given spec.
     *
     * @return The context that was used for printing.
     * @throws InterruptedException
     */
    public RenderingContext print(PJsonObject jsonSpec, OutputStream outputStream, Map headers) throws DocumentException, InterruptedException {
        final Timer.Context timer = metricRegistry.timer(getClass().getName()).time();
        try {
            initFonts();
            OutputFormat output = this.outputFactory.create(config, jsonSpec);

            PrintParams params = new PrintParams(config, configDir, jsonSpec, outputStream, headers);
            return output.print(params);
        } finally {
            final long printTime = timer.stop();
            if (TimeUnit.SECONDS.toNanos(getConfig().getMaxPrintTimeBeforeWarningInSeconds()) < printTime) {
                LOGGER.warn("[Overtime Print] "+jsonSpec.getInternalObj());
            }
        }
    }

    public static PJsonObject parseSpec(String spec) {
        final JSONObject jsonSpec;
        try {
            jsonSpec = new JSONObject(spec);
        } catch (JSONException e) {

            throw new RuntimeException("Cannot parse the spec file: " + e.getMessage() + ": " + spec, e);
        }
        return new PJsonObject(jsonSpec, "spec");
    }

    /**
     * Use by /info.json to generate its returned content.
     * @param json the writer for outputting the config specification
     */
    public void printClientConfig(JSONWriter json) throws JSONException {
        config.printClientConfig(json);
    }

    /**
     * Stop the thread pool or others.
     */
    @PreDestroy
    public synchronized void stop() {
        usages--;
        if (config != null && usages <= 0) {
            usages = 0;
            config.close();
            config = null;
        }
    }
    
    public synchronized void start() {
        usages++;
    }

    public String getOutputFilename(String layout, String defaultName) {
        final String name = config.getOutputFilename(layout);
        return name == null ? defaultName : name;
    }

    public Config getConfig() {
        return config;
    }
    public OutputFormat getOutputFormat(PJsonObject jsonSpec) {
        return outputFactory.create(config, jsonSpec);
    }

    public boolean isRunning() {
        return this.config != null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy