1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.component.wiki.internal

File DefaultWikiComponentMethodExecutor.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart0.png
86% of files have more coverage

Code metrics

10
33
3
1
207
115
13
0.39
11
3
4.33

Classes

Class Line # Actions
DefaultWikiComponentMethodExecutor 56 33 0% 13 46
0.00%
 

Contributing tests

No tests hitting this source file were found.

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.component.wiki.internal;
21   
22    import java.lang.reflect.Method;
23    import java.util.HashMap;
24    import java.util.Map;
25   
26    import javax.inject.Inject;
27    import javax.inject.Named;
28    import javax.inject.Singleton;
29   
30    import org.xwiki.bridge.DocumentAccessBridge;
31    import org.xwiki.component.annotation.Component;
32    import org.xwiki.component.wiki.WikiComponentRuntimeException;
33    import org.xwiki.context.Execution;
34    import org.xwiki.model.reference.DocumentReference;
35    import org.xwiki.properties.ConverterManager;
36    import org.xwiki.properties.converter.ConversionException;
37    import org.xwiki.rendering.block.XDOM;
38    import org.xwiki.rendering.internal.transformation.MutableRenderingContext;
39    import org.xwiki.rendering.renderer.BlockRenderer;
40    import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter;
41    import org.xwiki.rendering.renderer.printer.WikiPrinter;
42    import org.xwiki.rendering.syntax.Syntax;
43    import org.xwiki.rendering.transformation.RenderingContext;
44    import org.xwiki.rendering.transformation.Transformation;
45    import org.xwiki.rendering.transformation.TransformationContext;
46    import org.xwiki.rendering.transformation.TransformationException;
47   
48    /**
49    * Default {@link WikiComponentMethodExecutor}.
50    *
51    * @version $Id: 531b4d1ca9ab4046e8cbc7d71595b91de6eb25ba $
52    * @since 4.3M2
53    */
54    @Component
55    @Singleton
 
56    public class DefaultWikiComponentMethodExecutor implements WikiComponentMethodExecutor
57    {
58    /**
59    * The key under which the context document is kept in the XWiki context.
60    */
61    private static final String XWIKI_CONTEXT_DOC_KEY = "doc";
62   
63    /**
64    * The execution context.
65    */
66    @Inject
67    private Execution execution;
68   
69    /**
70    * Used to update the rendering context.
71    */
72    @Inject
73    private RenderingContext renderingContext;
74   
75    /**
76    * Macro transformation engine.
77    */
78    @Inject
79    @Named("macro")
80    private Transformation macroTransformation;
81   
82    /**
83    * Renderer used to get the return value from the rendered content.
84    */
85    @Inject
86    @Named("plain/1.0")
87    private BlockRenderer blockRenderer;
88   
89    /**
90    * Converter used to cast the return value from the rendered content (String).
91    */
92    @Inject
93    private ConverterManager converterManager;
94   
95    /**
96    * Used to retrieve the component document.
97    */
98    @Inject
99    private DocumentAccessBridge dab;
100   
101    /**
102    * Prepare the method execution context.
103    *
104    * @param methodContext The context to populate
105    * @param args The arguments initially passed to the method
106    */
 
107  0 toggle private void prepareMethodContext(Map<String, Object> methodContext, Object[] args)
108    {
109  0 methodContext.put(OUTPUT_KEY, new WikiMethodOutputHandler());
110   
111  0 Map<Integer, Object> inputs = new HashMap<Integer, Object>();
112  0 if (args != null && args.length > 0) {
113    // Start with "0" as first input key.
114  0 for (int i = 0; i < args.length; i++) {
115  0 inputs.put(i, args[i]);
116    }
117    }
118  0 methodContext.put(INPUT_KEY, inputs);
119    }
120   
121    /**
122    * Render a XDOM and return a value converted from the rendered content. The type matches the return value of the
123    * passed method.
124    *
125    * @param xdom The XDOM to render
126    * @param method The method called
127    * @return A value matching the method return type
128    * @throws WikiComponentRuntimeException When the conversion fails
129    */
 
130  0 toggle private Object castRenderedContent(XDOM xdom, Method method) throws WikiComponentRuntimeException
131    {
132    // Since no return value has been explicitly provided, we try to convert the result of the rendering
133    // into the expected return type using a Converter.
134  0 WikiPrinter printer = new DefaultWikiPrinter();
135  0 blockRenderer.render(xdom, printer);
136  0 String contentResult = printer.toString();
137   
138    // Do the conversion!
139  0 try {
140  0 return converterManager.convert(method.getGenericReturnType(), contentResult);
141    } catch (ConversionException e) {
142    // Surrender!
143  0 throw new WikiComponentRuntimeException(
144    String.format("Failed to convert result [%s] to type [%s] for method [%s.%s]",
145    contentResult,
146    method.getGenericReturnType(),
147    method.getDeclaringClass().getName(),
148    method.getName()), e);
149    }
150    }
151   
 
152  0 toggle @Override
153    public Object execute(Method method, Object[] args, DocumentReference componentDocumentReference, XDOM xdom,
154    Syntax syntax, Map<String, Object> methodContext)
155    throws WikiComponentRuntimeException
156    {
157    // Prepare and put the method context in the XWiki Context
158  0 Map<Object, Object> xwikiContext = (Map<Object, Object>) execution.getContext().getProperty("xwikicontext");
159  0 this.prepareMethodContext(methodContext, args);
160  0 xwikiContext.put("method", methodContext);
161    // Save current context document, to put it back after the execution.
162  0 Object contextDoc = xwikiContext.get(XWIKI_CONTEXT_DOC_KEY);
163   
164  0 try {
165    // Put component document in the context, so that macro transformation rights are checked against the
166    // component document and not the context one.
167  0 try {
168  0 xwikiContext.put(XWIKI_CONTEXT_DOC_KEY, dab.getDocumentInstance(componentDocumentReference));
169    } catch (Exception e) {
170  0 throw new WikiComponentRuntimeException(String.format(
171    "Failed to load wiki component document [%s]", componentDocumentReference), e);
172    }
173   
174    // We need to clone the xdom to avoid transforming the original and make it useless after the first
175    // transformation
176  0 XDOM transformedXDOM = xdom.clone();
177   
178    // Perform internal macro transformations
179  0 try {
180  0 TransformationContext transformationContext = new TransformationContext(transformedXDOM, syntax);
181  0 transformationContext.setId(method.getClass().getName() + "#" + method.getName());
182  0 ((MutableRenderingContext) renderingContext).transformInContext(macroTransformation,
183    transformationContext, transformedXDOM);
184    } catch (TransformationException e) {
185  0 throw new WikiComponentRuntimeException(String.format(
186    "Error while executing wiki component macro transformation for method [%s]", method.getName()), e);
187    }
188   
189  0 if (!method.getReturnType().getName().equals("void")) {
190  0 if (methodContext.get(OUTPUT_KEY) != null
191    && ((WikiMethodOutputHandler)
192    methodContext.get(OUTPUT_KEY)).getValue() != null) {
193  0 return method.getReturnType().cast(((WikiMethodOutputHandler)
194    methodContext.get(OUTPUT_KEY)).getValue());
195    } else {
196  0 return this.castRenderedContent(transformedXDOM, method);
197    }
198    } else {
199  0 return null;
200    }
201    } finally {
202  0 if (contextDoc != null) {
203  0 xwikiContext.put(XWIKI_CONTEXT_DOC_KEY, contextDoc);
204    }
205    }
206    }
207    }