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

org.mapfish.print.output.Values Maven / Gradle / Ivy

package org.mapfish.print.output;

import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.vividsolutions.jts.util.Assert;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mapfish.print.attribute.Attribute;
import org.mapfish.print.attribute.DataSourceAttribute;
import org.mapfish.print.attribute.HttpRequestHeadersAttribute;
import org.mapfish.print.attribute.PrimitiveAttribute;
import org.mapfish.print.attribute.ReflectiveAttribute;
import org.mapfish.print.config.PDFConfig;
import org.mapfish.print.config.Template;
import org.mapfish.print.http.ConfigFileResolvingHttpRequestFactory;
import org.mapfish.print.http.MfClientHttpRequestFactory;
import org.mapfish.print.http.MfClientHttpRequestFactoryImpl;
import org.mapfish.print.parser.MapfishParser;
import org.mapfish.print.servlet.MapPrinterServlet;
import org.mapfish.print.wrapper.ObjectMissingException;
import org.mapfish.print.wrapper.PObject;
import org.mapfish.print.wrapper.json.PJsonArray;
import org.mapfish.print.wrapper.json.PJsonObject;
import org.mapfish.print.wrapper.multi.PMultiObject;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static org.mapfish.print.servlet.MapPrinterServlet.JSON_REQUEST_HEADERS;

/**
 * Values that go into a processor from previous processors in the processor processing graph.
 *
 * @author Jesse
 */
public final class Values {
    /**
     * The key that is used to store the task directory in the values map.
     */
    public static final String TASK_DIRECTORY_KEY = "tempTaskDirectory";
    /**
     * The key that is used to store {@link org.mapfish.print.http.MfClientHttpRequestFactory}.
     */
    public static final String CLIENT_HTTP_REQUEST_FACTORY_KEY = "clientHttpRequestFactory";
    /**
     * The key that is used to store {@link org.mapfish.print.config.Template}.
     */
    public static final String TEMPLATE_KEY = "template";
    /**
     * The key for the values object for the {@link org.mapfish.print.config.PDFConfig} object.
     */
    public static final String PDF_CONFIG = "pdfConfig";
    /**
     * The key for the values object for the subreport directory.
     */
    public static final String SUBREPORT_DIR = "SUBREPORT_DIR";


    private final Map values = new ConcurrentHashMap();

    /**
     * Constructor.
     *
     * @param values initial values.
     */
    public Values(final Map values) {
        this.values.putAll(values);
    }

    /**
     * Constructor.
     */
    public Values() {
        // nothing to do
    }

    /**
     * Construct from the json request body and the associated template.
     *
     * @param requestData         the json request data
     * @param template            the template
     * @param parser              the parser to use for parsing the request data.
     * @param taskDirectory       the temporary directory for this printing task.
     * @param httpRequestFactory  a factory for making http requests.
     * @param jasperTemplateBuild the directory where the jasper templates are compiled to
     */
    public Values(final PJsonObject requestData,
                  final Template template,
                  final MapfishParser parser,
                  final File taskDirectory,
                  final MfClientHttpRequestFactoryImpl httpRequestFactory,
                  final File jasperTemplateBuild) throws JSONException {

        Assert.isTrue(!taskDirectory.mkdirs() || taskDirectory.exists());

        // add task dir. to values so that all processors can access it
        this.values.put(TASK_DIRECTORY_KEY, taskDirectory);
        this.values.put(CLIENT_HTTP_REQUEST_FACTORY_KEY, new ConfigFileResolvingHttpRequestFactory(httpRequestFactory,
                template.getConfiguration()));
        this.values.put(TEMPLATE_KEY, template);
        this.values.put(PDF_CONFIG, template.getPdfConfig());
        this.values.put(SUBREPORT_DIR, jasperTemplateBuild.getAbsolutePath());

        final PJsonObject jsonAttributes = requestData.getJSONObject(MapPrinterServlet.JSON_ATTRIBUTES);

        Map attributes = Maps.newHashMap(template.getAttributes());
        populateFromAttributes(template, parser, attributes, jsonAttributes);
    }

    /**
     * Process the requestJsonAttributes using the attributes and the MapfishParser and add all resulting values to this values object.
     *
     * @param template              the template of the current request.
     * @param parser                the parser to use for parsing the request data.
     * @param attributes            the attributes that will be used to add values to this values object
     * @param requestJsonAttributes the json data for populating the attribute values
     * @throws JSONException
     */
    public void populateFromAttributes(@Nonnull final Template template,
                                       @Nonnull final MapfishParser parser,
                                       @Nonnull final Map attributes,
                                       @Nonnull final PObject requestJsonAttributes) throws JSONException {
        if (requestJsonAttributes.has(JSON_REQUEST_HEADERS) &&
            requestJsonAttributes.getObject(JSON_REQUEST_HEADERS).has(JSON_REQUEST_HEADERS)) {
            if (!attributes.containsKey(MapPrinterServlet.JSON_REQUEST_HEADERS)) {
                attributes.put(MapPrinterServlet.JSON_REQUEST_HEADERS, new HttpRequestHeadersAttribute());
            }
        }
        for (String attributeName : attributes.keySet()) {
            final Attribute attribute = attributes.get(attributeName);
            final Object value;
            try {
                if (attribute instanceof PrimitiveAttribute) {
                    PrimitiveAttribute pAtt = (PrimitiveAttribute) attribute;
                    Object defaultVal = pAtt.getDefault();
                    PObject jsonToUse = requestJsonAttributes;
                    if (defaultVal != null) {
                        final JSONObject obj = new JSONObject();
                        obj.put(attributeName, defaultVal);
                        PObject[] pValues = new PObject[]{requestJsonAttributes, new PJsonObject(obj, "default_" + attributeName)};
                        jsonToUse = new PMultiObject(pValues);
                    }
                    value = parser.parsePrimitive(attributeName, pAtt, jsonToUse);
                } else if (attribute instanceof DataSourceAttribute) {
                    DataSourceAttribute dsAttribute = (DataSourceAttribute) attribute;
                    value = dsAttribute.parseAttribute(parser, template, requestJsonAttributes.optArray(attributeName));
                } else if (attribute instanceof ReflectiveAttribute) {
                    boolean errorOnExtraParameters = template.getConfiguration().isThrowErrorOnExtraParameters();
                    ReflectiveAttribute rAtt = (ReflectiveAttribute) attribute;
                    value = rAtt.createValue(template);
                    PObject pValue = requestJsonAttributes.optObject(attributeName);

                    if (pValue != null) {
                        PObject[] pValues = new PObject[]{pValue, rAtt.getDefaultValue()};
                        pValue = new PMultiObject(pValues);
                    } else {
                        final Object valueOpt = requestJsonAttributes.opt(attributeName);
                        if (valueOpt != null) {
                            String valueAsString;
                            if (valueOpt instanceof PJsonArray) {
                                valueAsString = ((PJsonArray) valueOpt).getInternalArray().toString(2);
                            } else if (valueOpt instanceof JSONArray) {
                                valueAsString = ((JSONArray) valueOpt).toString(2);
                            } else {
                                valueAsString = valueOpt.toString();
                            }
                            final String message = "Expected a JSON Object as the value for the element with the path: '" +
                                                   requestJsonAttributes.getPath(attributeName) + "' but instead "
                                                   + "got a '" + valueOpt.getClass().toString() +
                                                   "'.\nThe value is: \n" + valueAsString;
                            throw new IllegalArgumentException(message);
                        }
                        pValue = rAtt.getDefaultValue();
                    }
                    parser.parse(errorOnExtraParameters, pValue, value);
                } else {
                    throw new IllegalArgumentException("Unsupported attribute type: " + attribute);
                }
                put(attributeName, value);
            } catch (ObjectMissingException e) {
                throw e;
            } catch (IllegalArgumentException e) {
                throw e;
            } catch (Throwable e) {
                String templateName = "unknown";
                for (Map.Entry entry : template.getConfiguration().getTemplates().entrySet()) {
                    if (entry.getValue() == template) {
                        templateName = entry.getKey();
                    }
                }

                String defaults = "";

                if (attribute instanceof ReflectiveAttribute) {
                    ReflectiveAttribute reflectiveAttribute = (ReflectiveAttribute) attribute;
                    defaults = "\n\n The attribute defaults are: " + reflectiveAttribute.getDefaultValue();
                }

                String errorMsg = "An error occurred when creating a value from the '" + attributeName + "' attribute for the '" +
                                  templateName + "' template.\n\nThe JSON is: \n" + requestJsonAttributes + defaults;

                throw new AttributeParsingException(errorMsg, e);
            }
        }
    }

    /**
     * Create a new instance and copy the required elements from the other values object.
     * (IE working directory, http client factory, etc...)
     *
     * @param values the values containing the required elements
     */
    public Values(@Nonnull final Values values) {
        addRequiredValues(values);
    }

    /**
     * Add the elements that all values objects require from the provided values object.
     *
     * @param sourceValues the values object containing the required elements
     */
    public void addRequiredValues(@Nonnull final Values sourceValues) {
        Object taskDirectory = sourceValues.getObject(TASK_DIRECTORY_KEY, Object.class);
        MfClientHttpRequestFactory requestFactory = sourceValues.getObject(CLIENT_HTTP_REQUEST_FACTORY_KEY,
                MfClientHttpRequestFactory.class);
        Template template = sourceValues.getObject(TEMPLATE_KEY, Template.class);
        PDFConfig pdfConfig = sourceValues.getObject(PDF_CONFIG, PDFConfig.class);
        String subReportDir = sourceValues.getObject(SUBREPORT_DIR, String.class);

        this.values.put(TASK_DIRECTORY_KEY, taskDirectory);
        this.values.put(CLIENT_HTTP_REQUEST_FACTORY_KEY, requestFactory);
        this.values.put(TEMPLATE_KEY, template);
        this.values.put(PDF_CONFIG, pdfConfig);
        this.values.put(SUBREPORT_DIR, subReportDir);

    }

    /**
     * Put a new value in map.
     *
     * @param key   id of the value for looking up.
     * @param value the value.
     */
    public void put(final String key, final Object value) {
        if (TASK_DIRECTORY_KEY.equals(key) && this.values.keySet().contains(TASK_DIRECTORY_KEY)) {
            // ensure that no one overwrites the task directory
            throw new IllegalArgumentException("Invalid key: " + key);
        }

        if (value == null) {
            throw new IllegalArgumentException("A null value was attempted to be put into the values object under key: " + key);
        }
        this.values.put(key, value);
    }

    /**
     * Get all parameters.
     */
    public Map asMap() {
        return this.values;
    }

    /**
     * Get a value as a string.
     *
     * @param key the key for looking up the value.
     */
    public String getString(final String key) {
        return (String) this.values.get(key);
    }

    /**
     * Get a value as a double.
     *
     * @param key the key for looking up the value.
     */
    public Double getDouble(final String key) {
        return (Double) this.values.get(key);
    }

    /**
     * Get a value as a integer.
     *
     * @param key the key for looking up the value.
     */
    public Integer getInteger(final String key) {
        return (Integer) this.values.get(key);
    }

    /**
     * Get a value as a string.
     *
     * @param key  the key for looking up the value.
     * @param type the type of the object
     * @param   the type
     */
    public  V getObject(final String key, final Class type) {
        final Object obj = this.values.get(key);
        return type.cast(obj);
    }

    /**
     * Return true if the identified value is present in this values.
     *
     * @param key the key to check for.
     */
    public boolean containsKey(final String key) {
        return this.values.containsKey(key);
    }

    /**
     * Get a boolean value from the values or null.
     *
     * @param key the look up key of the value
     */
    @Nullable
    public Boolean getBoolean(@Nonnull final String key) {
        return (Boolean) this.values.get(key);
    }

    /**
     * Remove a value from this object.
     *
     * @param key key of entry to remove.
     */
    public void remove(final String key) {
        this.values.remove(key);
    }

    /**
     * Find all the values of the requested type.
     *
     * @param valueTypeToFind the type of the value to return.
     * @param              the type of the value to find.
     * @return the key, value pairs found.
     */
    @SuppressWarnings("unchecked")
    public  Map find(final Class valueTypeToFind) {
        final Map filtered = Maps.filterEntries(this.values, new Predicate>() {
            @Override
            public boolean apply(@Nullable final Map.Entry input) {
                return input != null && valueTypeToFind.isInstance(input.getValue());
            }
        });

        return (Map) filtered;
    }

    @Override
    public String toString() {
        return this.values.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy