/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2016 Open Source Geospatial Foundation (OSGeo) * (C) 2014-2016 Boundless Spatial * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.ysld.encode; import static org.geotools.ysld.ProcessUtil.loadProcessFunctionFactory; import static org.geotools.ysld.ProcessUtil.loadProcessInfo; import static org.geotools.ysld.ProcessUtil.processName; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.geotools.data.Parameter; import org.geotools.ysld.ProcessUtil; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; /** * Encodes a Rendering Transform, represented by an {@link Expression} as YSLD. */ public class TransformEncoder extends YsldEncodeHandler<Expression> { boolean chained; public TransformEncoder(Expression tx) { this(tx, false); } public TransformEncoder(Expression tx, boolean chained) { super(tx); this.chained = chained; } @Override protected void encode(Expression tx) { if (loadProcessFunctionFactory() == null) { FeatureStyleEncoder.LOG.warning( "Skipping transform, unable to load process factory, ensure process modules installed"); return; } if (!(tx instanceof Function)) { FeatureStyleEncoder.LOG .warning("Skipping transform, expected a function but got: " + tx); return; } Function ftx = (Function) tx; Map<String, Parameter<?>> paramInfo = loadProcessInfo(processName(ftx.getName())); if (paramInfo == null) { FeatureStyleEncoder.LOG.warning( "Skipping transform, unable to locate process named: " + ftx.getName()); return; } boolean wmsParams = ProcessUtil.hasWMSParams(paramInfo); put("name", ftx.getName()); Map<String, Object> simpleParams = new LinkedHashMap<String, Object>(); String input = null; for (Expression expr : ftx.getParameters()) { if (!(expr instanceof Function)) { FeatureStyleEncoder.LOG .warning("Skipping parameter, expected a function but got: " + expr); continue; } Function fexpr = (Function) expr; if (fexpr.getParameters().size() < 1) { FeatureStyleEncoder.LOG.warning("Skipping parameter, must have at least one value"); continue; } String paramName = fexpr.getParameters().get(0).evaluate(null, String.class); final Object paramValue; if (fexpr.getParameters().size() == 1) { // TODO: handle multiple input parameters. input = paramName; continue; // It's an input parameter so don't include it in the regular parameter list } else if (fexpr.getParameters().size() == 2) { paramValue = intermediateExpression(fexpr.getParameters().get(1)); } else { List<Object> l = new ArrayList<Object>(); for (int i = 1; i < fexpr.getParameters().size(); i++) { l.add(intermediateExpression(fexpr.getParameters().get(i))); } paramValue = l; } // If the process is a rendering transformation and the parameter is one of the WMS // environment parameters with its default values, then skip it as it will be filled in // when parsed. if (!(wmsParams && isDefaultWMSParam(paramName, paramValue))) { simpleParams.put(paramName, paramValue); } } if (input != null && (chained || !input.equals("data"))) { put("input", input); } push("params").inline(simpleParams); } private boolean isDefaultWMSParam(String paramName, final Object paramValue) { if (paramName.equals("outputBBOX") && paramValue.equals("${env('wms_bbox')}")) return true; if (paramName.equals("outputWidth") && paramValue.equals("${env('wms_width')}")) return true; if (paramName.equals("outputHeight") && paramValue.equals("${env('wms_height')}")) return true; return false; } Object intermediateExpression(Expression e) { if (ProcessUtil.isProcess(e)) { chained = true; TransformEncoder enc = new TransformEncoder(e, true); enc.reset(); enc.encode(e); return enc.root(); } else { return toObjOrNull(e); } } }