001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.console.freemarker; 018 019import java.io.*; 020import java.util.*; 021 022import org.apache.juneau.marshall.collections.*; 023import org.apache.juneau.marshall.json5.*; 024 025import freemarker.core.*; 026import freemarker.template.*; 027 028/** 029 * The {@code <@facts>} FreeMarker twin of the {@code <@console facts=>} attribute: a JSON5 object body, merged 030 * last-wins with any other chrome-side facts. Repeatable; the one strict check against Java-seeded facts happens 031 * once, at {@code </@console>}. 032 * 033 * <h5 class='section'>Example:</h5> 034 * <p class='bcode'> 035 * <@facts>{"buildVersion": "1.0"}</@facts> 036 * </p> 037 * 038 * @since 10.0.0 039 */ 040public final class FactsDirectiveModel implements TemplateDirectiveModel { 041 042 /** The shared-variable name this directive registers under. */ 043 public static final String NAME = "facts"; 044 045 FactsDirectiveModel() {} 046 047 @Override 048 @SuppressWarnings({ 049 "unchecked" // FreeMarker's raw params Map is String-keyed by contract. 050 }) 051 public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars, 052 TemplateDirectiveBody body) throws TemplateException, IOException { 053 Map<String, TemplateModel> p = params; 054 if (p.containsKey("format")) 055 throw FtlAttrLists.reject("<@facts> has no format= attribute."); 056 FtlAttrLists.rejectUnknown(p, NAME, Set.of()); 057 058 var cap = PageCapture.get(env); 059 if (cap == null || ! cap.consoleOpen) 060 throw FtlAttrLists.reject("<@facts> must be nested inside <@console>."); 061 062 var markup = PageCapture.render(body); 063 if (markup.isBlank()) 064 return; 065 JsonMap parsed; 066 try { 067 parsed = Json5Parser.DEFAULT.read(markup.trim(), JsonMap.class); 068 } catch (org.apache.juneau.marshall.parser.ParseException e) { 069 throw FtlAttrLists.reject("<@facts> body is not valid JSON5: " + e.getMessage()); 070 } 071 cap.mergeChromeFacts(parsed); 072 } 073}