1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.templatingcomponents.freemarker;
35
36 import freemarker.core.CollectionAndSequence;
37 import freemarker.core.Environment;
38 import freemarker.template.TemplateBooleanModel;
39 import freemarker.template.TemplateCollectionModel;
40 import freemarker.template.TemplateDirectiveBody;
41 import freemarker.template.TemplateDirectiveModel;
42 import freemarker.template.TemplateException;
43 import freemarker.template.TemplateModel;
44 import freemarker.template.TemplateModelException;
45 import freemarker.template.TemplateScalarModel;
46 import freemarker.template.TemplateSequenceModel;
47 import info.magnolia.cms.beans.config.ServerConfiguration;
48 import info.magnolia.cms.core.AggregationState;
49 import info.magnolia.cms.core.Content;
50 import info.magnolia.context.MgnlContext;
51 import info.magnolia.freemarker.models.ContentModel;
52 import info.magnolia.module.templatingcomponents.AuthoringUiComponent;
53
54 import java.io.IOException;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.Map;
59
60
61
62
63
64 public abstract class AbstractDirective implements TemplateDirectiveModel {
65
66 @SuppressWarnings("unchecked")
67 public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
68 final ServerConfiguration serverConfiguration = ServerConfiguration.getInstance();
69 final AggregationState aggregationState = MgnlContext.getAggregationState();
70 final AuthoringUiComponent uiComp = prepareUIComponent(serverConfiguration, aggregationState, env, params, loopVars, body);
71
72
73 if (!params.isEmpty()) {
74 throw new TemplateModelException("Unsupported parameter(s): " + params);
75 }
76
77 uiComp.render(env.getOut());
78
79 try {
80 doBody(env, body);
81 } finally {
82 uiComp.postRender();
83 }
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98 protected abstract AuthoringUiComponent prepareUIComponent(ServerConfiguration serverCfg, AggregationState aggState, Environment env, Map<String, TemplateModel> params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateModelException, IOException;
99
100 protected void doBody(Environment env, TemplateDirectiveBody body) throws TemplateException, IOException {
101 if (body != null) {
102 body.render(env.getOut());
103 }
104 }
105
106
107
108
109
110 protected void checkBody(TemplateDirectiveBody body, boolean needsBody) throws TemplateModelException {
111 if ((body == null) == needsBody) {
112 throw new TemplateModelException("This directive " + (needsBody ? "needs a body" : "does not support a body"));
113 }
114 }
115
116 protected String mandatoryString(Map<String, TemplateModel> params, String key) throws TemplateModelException {
117 return _param(params, key, TemplateScalarModel.class, true).getAsString();
118 }
119
120 protected String string(Map<String, TemplateModel> params, String key, String defaultValue) throws TemplateModelException {
121 final TemplateScalarModel m = _param(params, key, TemplateScalarModel.class, false);
122 if (m == null) {
123 return defaultValue;
124 }
125 return m.getAsString();
126 }
127
128 protected boolean mandatoryBool(Map<String, TemplateModel> params, String key) throws TemplateModelException {
129 return _param(params, key, TemplateBooleanModel.class, true).getAsBoolean();
130 }
131
132 protected boolean bool(Map<String, TemplateModel> params, String key, boolean defaultValue) throws TemplateModelException {
133 final TemplateBooleanModel m = _param(params, key, TemplateBooleanModel.class, false);
134 if (m == null) {
135 return defaultValue;
136 }
137 return m.getAsBoolean();
138 }
139
140 protected Content mandatoryContent(Map<String, TemplateModel> params, String key) throws TemplateModelException {
141 return _param(params, key, ContentModel.class, true).asContent();
142 }
143
144 protected Content content(Map<String, TemplateModel> params, String key, Content defaultValue) throws TemplateModelException {
145 final ContentModel m = _param(params, key, ContentModel.class, false);
146 if (m == null) {
147 return defaultValue;
148 }
149 return m.asContent();
150 }
151
152 protected List<String> mandatoryStringList(Map<String, TemplateModel> params, String key) throws TemplateModelException {
153 final TemplateModel model = _param(params, key, TemplateModel.class, true);
154 if (model instanceof TemplateScalarModel) {
155 final String s = ((TemplateScalarModel) model).getAsString();
156 return Collections.singletonList(s);
157 } else if (model instanceof TemplateSequenceModel) {
158 final CollectionAndSequence coll = new CollectionAndSequence((TemplateSequenceModel) model);
159 return unwrapStringList(coll, key);
160 } else if (model instanceof TemplateCollectionModel) {
161 final CollectionAndSequence coll = new CollectionAndSequence((TemplateCollectionModel) model);
162 return unwrapStringList(coll, key);
163 } else {
164 throw new TemplateModelException(key + " must be a String, a Collection of Strings. Found " + model.getClass().getSimpleName() + ".");
165 }
166 }
167
168 private List<String> unwrapStringList(CollectionAndSequence collAndSeq, String key) throws TemplateModelException {
169 final List<String> list = new ArrayList<String>();
170 for (int i = 0; i < collAndSeq.size(); i++) {
171 final TemplateModel tm = collAndSeq.get(i);
172 if (!(tm instanceof TemplateScalarModel)) {
173 throw new TemplateModelException("The '" + key + "' attribute must be a String or a Collection of Strings. Found Collection of " + tm.getClass().getSimpleName() + ".");
174 } else {
175 list.add(((TemplateScalarModel) tm).getAsString());
176 }
177 }
178 return list;
179 }
180
181 protected <MT extends TemplateModel> MT _param(Map<String, TemplateModel> params, String key, Class<MT> type, boolean isMandatory) throws TemplateModelException {
182 final boolean containsKey = params.containsKey(key);
183 if (isMandatory && !containsKey) {
184 throw new TemplateModelException("The '" + key + "' parameter is mandatory.");
185
186 }
187
188 final TemplateModel m = params.get(key);
189 if (m != null && !type.isAssignableFrom(m.getClass())) {
190 throw new TemplateModelException("The '" + key + "' parameter must be a " + type.getSimpleName() + " and is a " + m.getClass().getSimpleName() + ".");
191 }
192 if (m == null && containsKey) {
193
194 throw new TemplateModelException("The '" + key + "' parameter was passed but not or wrongly specified.");
195 }
196 if (containsKey) {
197 params.remove(key);
198 }
199
200 return (MT) m;
201 }
202 }