/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.script.function; import static org.apache.commons.io.FilenameUtils.getBaseName; import static org.apache.commons.io.FilenameUtils.getExtension; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.geoserver.platform.resource.Resource; import org.geoserver.platform.resource.Resources; import org.geoserver.script.ScriptFactory; import org.geoserver.script.ScriptManager; import org.geoserver.script.wps.ScriptProcessFactory; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.NameImpl; import org.geotools.filter.FunctionFactory; import org.geotools.util.SoftValueHashMap; import org.geotools.util.logging.Logging; import org.opengis.feature.type.Name; import org.opengis.filter.FilterFactory; import org.opengis.filter.capability.FunctionName; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; /** * Function factory that creates processes from scripts located in the data directory. */ public class ScriptFunctionFactory extends ScriptFactory implements FunctionFactory { /** logger */ static Logger LOGGER = Logging.getLogger(ScriptProcessFactory.class); /** script manager */ ScriptManager scriptMgr; SoftValueHashMap<Name, ScriptFunction> functions = new SoftValueHashMap<Name, ScriptFunction>(); public ScriptFunctionFactory() { super(null); } public ScriptFunctionFactory(ScriptManager scriptMgr) { super(scriptMgr); } @Override public List<FunctionName> getFunctionNames() { LOGGER.fine("Performing filter lookup"); FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); ScriptManager scriptMgr = scriptMgr(); List<FunctionName> names = new ArrayList<FunctionName>(); try { Resource filterRoot = scriptMgr.function(); for (Resource file : filterRoot.list()) { FunctionHook hook = scriptMgr.lookupFilterHook(file); if (!Resources.exists(file)) { LOGGER.fine("Skipping " + file.name() + ", no hook found"); } //TODO: support multiple functions in one file //TODO: support the function defining its namespace names.add(ff.functionName( new NameImpl(getExtension(file.name()), getBaseName(file.name())), -1)); } } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "Error looking up filters", e); } return names; } @Override public Function function(String name, List<Expression> args, Literal fallback) { return function(new NameImpl(name), args, fallback); } @Override public Function function(Name name, List<Expression> args, Literal fallback) { ScriptFunction f = function(name); return f != null ? f.instance(name, args) : null; } ScriptFunction function(Name name) { ScriptFunction function = functions.get(name); if (function == null) { synchronized(this) { function = functions.get(name); if (function == null) { ScriptManager scriptMgr = scriptMgr(); Resource filterRoot = scriptMgr.function(); Resource f = null; if (name.getNamespaceURI() != null) { f = filterRoot.get(name.getLocalPart() + "." + name.getNamespaceURI()); } else { //look for a file based on basename for (Resource file : filterRoot.list()) { if (name.getLocalPart().equals(getBaseName(file.name()))) { f = file; break; } } } if (f == null) { return null; } if (!Resources.exists(f)) { LOGGER.log(Level.WARNING, "File not found : " + f.path()); return null; } function = new ScriptFunction(f, scriptMgr); functions.put(name, function); } } } return function; } }