1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.rendering.macro.script

File AbstractScriptMacro.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

14
42
11
1
310
136
21
0.5
3.82
11
1.91

Classes

Class Line # Actions
AbstractScriptMacro 58 42 0% 21 17
0.7462686374.6%
 

Contributing tests

This file is covered by 60 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rendering.macro.script;
21   
22    import java.io.StringReader;
23    import java.util.Collections;
24    import java.util.List;
25   
26    import javax.inject.Inject;
27    import javax.inject.Named;
28   
29    import org.apache.commons.lang3.StringUtils;
30    import org.xwiki.context.Execution;
31    import org.xwiki.observation.ObservationManager;
32    import org.xwiki.rendering.block.Block;
33    import org.xwiki.rendering.block.MacroBlock;
34    import org.xwiki.rendering.macro.AbstractSignableMacro;
35    import org.xwiki.rendering.macro.MacroContentParser;
36    import org.xwiki.rendering.macro.MacroExecutionException;
37    import org.xwiki.rendering.macro.descriptor.ContentDescriptor;
38    import org.xwiki.rendering.parser.ParseException;
39    import org.xwiki.rendering.parser.Parser;
40    import org.xwiki.rendering.transformation.MacroTransformationContext;
41    import org.xwiki.rendering.util.ParserUtils;
42    import org.xwiki.script.event.ScriptEvaluatedEvent;
43    import org.xwiki.script.event.ScriptEvaluatingEvent;
44   
45    /**
46    * Base Class for script evaluation macros.
47    * <p>
48    * It is not obvious to see how macro execution works just from looking at the code. A lot of checking and
49    * initialization is done in listeners to the {@link org.xwiki.script.event.ScriptEvaluatingEvent} and
50    * {@link org.xwiki.script.event.ScriptEvaluatedEvent}. E.g. the check for programming rights for JSR223 scripts, check
51    * for nested script macros and selecting the right class loader is done there.
52    * </p>
53    *
54    * @param <P> the type of macro parameters bean.
55    * @version $Id: 4f35ffec60e0860ada33ac82e04b3de7621bb2f8 $
56    * @since 1.7M3
57    */
 
58    public abstract class AbstractScriptMacro<P extends ScriptMacroParameters> extends AbstractSignableMacro<P> implements
59    ScriptMacro
60    {
61    /**
62    * The default description of the script macro content.
63    */
64    protected static final String CONTENT_DESCRIPTION = "the script to execute";
65   
66    /**
67    * Used to find if the current document's author has programming rights.
68    *
69    * @deprecated since 2.5M1 (not used any more)
70    */
71    @Inject
72    @Deprecated
73    protected org.xwiki.bridge.DocumentAccessBridge documentAccessBridge;
74   
75    /**
76    * Used by subclasses.
77    */
78    @Inject
79    protected Execution execution;
80   
81    /**
82    * Used to parse the result of the script execution into a XDOM object when the macro is configured by the user to
83    * not interpret wiki syntax.
84    */
85    @Inject
86    @Named("plain/1.0")
87    private Parser plainTextParser;
88   
89    /**
90    * The parser used to parse box content and box title parameter.
91    */
92    @Inject
93    private MacroContentParser contentParser;
94   
95    /**
96    * Observation manager used to sent evaluation events.
97    */
98    @Inject
99    private ObservationManager observation;
100   
101    /**
102    * Utility to remove the top level paragraph.
103    */
104    private ParserUtils parserUtils = new ParserUtils();
105   
106    /**
107    * @param macroName the name of the macro (eg "groovy")
108    */
 
109  0 toggle public AbstractScriptMacro(String macroName)
110    {
111  0 super(macroName, null, ScriptMacroParameters.class);
112   
113  0 setDefaultCategory(DEFAULT_CATEGORY_DEVELOPMENT);
114    }
115   
116    /**
117    * @param macroName the name of the macro (eg "groovy")
118    * @param macroDescription the text description of the macro.
119    */
 
120  0 toggle public AbstractScriptMacro(String macroName, String macroDescription)
121    {
122  0 super(macroName, macroDescription, ScriptMacroParameters.class);
123   
124  0 setDefaultCategory(DEFAULT_CATEGORY_DEVELOPMENT);
125    }
126   
127    /**
128    * @param macroName the name of the macro (eg "groovy")
129    * @param macroDescription the text description of the macro.
130    * @param contentDescriptor the description of the macro content.
131    */
 
132  0 toggle public AbstractScriptMacro(String macroName, String macroDescription, ContentDescriptor contentDescriptor)
133    {
134  0 super(macroName, macroDescription, contentDescriptor, ScriptMacroParameters.class);
135   
136  0 setDefaultCategory(DEFAULT_CATEGORY_DEVELOPMENT);
137    }
138   
139    /**
140    * @param macroName the name of the macro (eg "groovy")
141    * @param macroDescription the text description of the macro.
142    * @param parametersBeanClass class of the parameters bean for this macro.
143    */
 
144  0 toggle public AbstractScriptMacro(String macroName, String macroDescription,
145    Class< ? extends ScriptMacroParameters> parametersBeanClass)
146    {
147  0 super(macroName, macroDescription, parametersBeanClass);
148   
149  0 setDefaultCategory(DEFAULT_CATEGORY_DEVELOPMENT);
150    }
151   
152    /**
153    * @param macroName the name of the macro (eg "groovy")
154    * @param macroDescription the text description of the macro.
155    * @param contentDescriptor the description of the macro content.
156    * @param parametersBeanClass class of the parameters bean for this macro.
157    */
 
158  93 toggle public AbstractScriptMacro(String macroName, String macroDescription, ContentDescriptor contentDescriptor,
159    Class< ? extends ScriptMacroParameters> parametersBeanClass)
160    {
161  93 super(macroName, macroDescription, contentDescriptor, parametersBeanClass);
162   
163  93 setDefaultCategory(DEFAULT_CATEGORY_DEVELOPMENT);
164    }
165   
 
166  8754 toggle @Override
167    public List<Block> execute(P parameters, String content, MacroTransformationContext context)
168    throws MacroExecutionException
169    {
170  8754 List<Block> result = Collections.emptyList();
171   
172  8754 if (StringUtils.isNotEmpty(content)) {
173  8750 try {
174    // send evaluation starts event
175  8750 ScriptEvaluatingEvent event = new ScriptEvaluatingEvent(getDescriptor().getId().getId());
176  8750 this.observation.notify(event, context, parameters);
177  8750 if (event.isCanceled()) {
178  7 throw new MacroExecutionException(event.getReason());
179    }
180   
181    // 2) Run script engine on macro block content
182  8743 List<Block> blocks = evaluateBlock(parameters, content, context);
183   
184  8742 if (parameters.isOutput()) {
185  7941 result = blocks;
186    }
187    } finally {
188    // send evaluation finished event
189  8750 this.observation.notify(new ScriptEvaluatedEvent(getDescriptor().getId().getId()), context, parameters);
190    }
191    }
192   
193  8746 return result;
194    }
195   
196    /**
197    * Convert script result as a {@link Block} list.
198    *
199    * @param content the script result to parse.
200    * @param parameters the macro parameters.
201    * @param context the context of the macro transformation.
202    * @return the {@link Block}s.
203    * @throws MacroExecutionException Failed to find source parser.
204    * @since 2.1M1
205    */
 
206  7942 toggle protected List<Block> parseScriptResult(String content, P parameters, MacroTransformationContext context)
207    throws MacroExecutionException
208    {
209  7942 List<Block> result;
210   
211  7943 if (parameters.isWiki()) {
212  7786 result = parseSourceSyntax(content, context);
213    } else {
214  157 try {
215  157 result = this.plainTextParser.parse(new StringReader(content)).getChildren();
216    } catch (ParseException e) {
217    // This shouldn't happen since the parser cannot throw an exception since the source is a memory
218    // String.
219  0 throw new MacroExecutionException("Failed to parse link label as plain text", e);
220    }
221    }
222   
223    // 3) If in inline mode remove any top level paragraph
224  7943 if (context.isInline()) {
225  114 this.parserUtils.removeTopLevelParagraph(result);
226   
227    // Make sure included macro is inline when script macro itself is inline
228    // TODO: use inline parser instead
229  114 if (!result.isEmpty() && result.get(0) instanceof MacroBlock && !((MacroBlock) result.get(0)).isInline()) {
230  34 MacroBlock macro = (MacroBlock) result.get(0);
231  34 result.set(0, new MacroBlock(macro.getId(), macro.getParameters(), macro.getContent(), true));
232    }
233    }
234   
235  7941 return result;
236    }
237   
238    /**
239    * Execute provided script.
240    *
241    * @param parameters the macro parameters.
242    * @param content the script to execute.
243    * @param context the context of the macro transformation.
244    * @return the result of script execution.
245    * @throws MacroExecutionException failed to evaluate provided content.
246    * @deprecated since 2.4M2 use {@link #evaluateString(ScriptMacroParameters, String, MacroTransformationContext)}
247    * instead
248    */
 
249  0 toggle @Deprecated
250    protected String evaluate(P parameters, String content, MacroTransformationContext context)
251    throws MacroExecutionException
252    {
253  0 return "";
254    }
255   
256    /**
257    * Execute provided script and return {@link String} based result.
258    *
259    * @param parameters the macro parameters.
260    * @param content the script to execute.
261    * @param context the context of the macro transformation.
262    * @return the result of script execution.
263    * @throws MacroExecutionException failed to evaluate provided content.
264    * @since 2.4M2
265    */
 
266  0 toggle protected String evaluateString(P parameters, String content, MacroTransformationContext context)
267    throws MacroExecutionException
268    {
269    // Call old method for retro-compatibility
270  0 return evaluate(parameters, content, context);
271    }
272   
273    /**
274    * Execute provided script and return {@link Block} based result.
275    *
276    * @param parameters the macro parameters.
277    * @param content the script to execute.
278    * @param context the context of the macro transformation.
279    * @return the result of script execution.
280    * @throws MacroExecutionException failed to evaluate provided content.
281    * @since 2.4M2
282    */
 
283  8630 toggle protected List<Block> evaluateBlock(P parameters, String content, MacroTransformationContext context)
284    throws MacroExecutionException
285    {
286  8630 String scriptResult = evaluateString(parameters, content, context);
287   
288  8630 List<Block> result = Collections.emptyList();
289  8630 if (parameters.isOutput()) {
290    // Run the wiki syntax parser on the script-rendered content
291  7832 result = parseScriptResult(scriptResult, parameters, context);
292    }
293   
294  8630 return result;
295    }
296   
297    /**
298    * Parse provided content with the parser of the current wiki syntax.
299    *
300    * @param content the content to parse.
301    * @param context the context of the macro transformation.
302    * @return the result of the parsing.
303    * @throws MacroExecutionException failed to parse content
304    */
 
305  7785 toggle protected List<Block> parseSourceSyntax(String content, MacroTransformationContext context)
306    throws MacroExecutionException
307    {
308  7786 return this.contentParser.parse(content, context, false, false).getChildren();
309    }
310    }