public Object exec()

in freemarker-core/src/main/java/freemarker/core/GetOptionalTemplateMethod.java [68:185]


    public Object exec(List args) throws TemplateModelException {
        final int argCnt = args.size();
        if (argCnt < 1 || argCnt > 2) {
            throw _MessageUtil.newArgCntError(methodName, argCnt, 1, 2);
        }

        final Environment env = Environment.getCurrentEnvironment();
        if (env == null) {
            throw new IllegalStateException("No freemarer.core.Environment is associated to the current thread.");
        }
        
        final String absTemplateName;
        {
            TemplateModel arg = (TemplateModel) args.get(0);
            if (!(arg instanceof TemplateScalarModel)) {
                throw _MessageUtil.newMethodArgMustBeStringException(methodName, 0, arg);
            }
            String templateName  = EvalUtil.modelToString((TemplateScalarModel) arg, null, env);
            
            try {
                absTemplateName = env.toFullTemplateName(env.getCurrentTemplate().getName(), templateName);
            } catch (MalformedTemplateNameException e) {
                throw new _TemplateModelException(
                        e, "Failed to convert template path to full path; see cause exception.");
            }
        }
        
        final TemplateHashModelEx options;
        if (argCnt > 1) {
            TemplateModel arg = (TemplateModel) args.get(1);
            if (!(arg instanceof TemplateHashModelEx)) {
                throw _MessageUtil.newMethodArgMustBeExtendedHashException(methodName, 1, arg);
            }
            options = (TemplateHashModelEx) arg;
        } else {
            options = null;
        }
        
        String encoding = null;
        boolean parse = true;
        if (options != null) {
            final KeyValuePairIterator kvpi = TemplateModelUtils.getKeyValuePairIterator(options);
            while (kvpi.hasNext()) {
                final KeyValuePair kvp = kvpi.next();
                
                final String optName;
                {
                    TemplateModel optNameTM = kvp.getKey();
                    if (!(optNameTM instanceof TemplateScalarModel)) {
                        throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
                                "All keys in the options hash must be strings, but found ",
                                new _DelayedAOrAn(new _DelayedFTLTypeDescription(optNameTM)));
                    }
                    optName = ((TemplateScalarModel) optNameTM).getAsString();
                }
                
                final TemplateModel optValue = kvp.getValue();
                
                if (OPTION_ENCODING.equals(optName)) {
                    encoding = getStringOption(OPTION_ENCODING, optValue); 
                } else if (OPTION_PARSE.equals(optName)) {
                    parse = getBooleanOption(OPTION_PARSE, optValue); 
                } else {
                    throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
                            "Unsupported option ", new _DelayedJQuote(optName), "; valid names are: ",
                            new _DelayedJQuote(OPTION_ENCODING), ", ", new _DelayedJQuote(OPTION_PARSE), ".");
                }
            }
        }

        final Template template;
        try {
            template = env.getTemplateForInclusion(absTemplateName, encoding, parse, true);
        } catch (IOException e) {
            throw new _TemplateModelException(
                    e, "I/O error when trying to load optional template ", new _DelayedJQuote(absTemplateName),
                        "; see cause exception");
        }
        
        SimpleHash result = new SimpleHash(_ObjectWrappers.SAFE_OBJECT_WRAPPER);
        result.put(RESULT_EXISTS, template != null);
        // If the template is missing, result.include and such will be missing too, so that a default can be
        // conveniently provided like in <@optTemp.include!myDefaultMacro />.
        if (template != null) {
            result.put(RESULT_INCLUDE, new TemplateDirectiveModel() {
                @Override
                public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
                        throws TemplateException, IOException {
                    if (!params.isEmpty()) {
                        throw new TemplateException("This directive supports no parameters.", env);
                    }
                    if (loopVars.length != 0) {
                        throw new TemplateException("This directive supports no loop variables.", env);
                    }
                    if (body != null) {
                        throw new TemplateException("This directive supports no nested content.", env);
                    }
                    
                    env.include(template);
                }
            });
            result.put(RESULT_IMPORT, new TemplateMethodModelEx() {
                @Override
                public Object exec(List args) throws TemplateModelException {
                    if (!args.isEmpty()) {
                        throw new TemplateModelException("This method supports no parameters.");
                    }
                    
                    try {
                        return env.importLib(template, null);
                    } catch (IOException | TemplateException e) {
                        throw new _TemplateModelException(e, "Failed to import loaded template; see cause exception");
                    }
                }
            });
        }
        return result;
    }