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

File DefaultGadgetSource.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart6.png
69% of files have more coverage

Code metrics

10
77
7
1
292
178
12
0.16
11
7
1.71

Classes

Class Line # Actions
DefaultGadgetSource 72 77 0% 12 45
0.521276652.1%
 

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.rendering.internal.macro.dashboard;
21   
22    import java.io.StringWriter;
23    import java.util.ArrayList;
24    import java.util.Collections;
25    import java.util.List;
26   
27    import javax.inject.Inject;
28    import javax.inject.Named;
29    import javax.inject.Singleton;
30   
31    import org.apache.commons.lang3.StringUtils;
32    import org.apache.velocity.VelocityContext;
33    import org.xwiki.component.annotation.Component;
34    import org.xwiki.context.Execution;
35    import org.xwiki.model.EntityType;
36    import org.xwiki.model.reference.DocumentReference;
37    import org.xwiki.model.reference.DocumentReferenceResolver;
38    import org.xwiki.model.reference.EntityReference;
39    import org.xwiki.model.reference.EntityReferenceSerializer;
40    import org.xwiki.rendering.block.Block;
41    import org.xwiki.rendering.block.GroupBlock;
42    import org.xwiki.rendering.block.LinkBlock;
43    import org.xwiki.rendering.block.WordBlock;
44    import org.xwiki.rendering.block.XDOM;
45    import org.xwiki.rendering.executor.ContentExecutor;
46    import org.xwiki.rendering.executor.ContentExecutorException;
47    import org.xwiki.rendering.listener.reference.ResourceReference;
48    import org.xwiki.rendering.listener.reference.ResourceType;
49    import org.xwiki.rendering.macro.dashboard.Gadget;
50    import org.xwiki.rendering.macro.dashboard.GadgetSource;
51    import org.xwiki.rendering.parser.MissingParserException;
52    import org.xwiki.rendering.parser.ParseException;
53    import org.xwiki.rendering.syntax.Syntax;
54    import org.xwiki.rendering.transformation.MacroTransformationContext;
55    import org.xwiki.rendering.util.ParserUtils;
56    import org.xwiki.velocity.VelocityEngine;
57    import org.xwiki.velocity.VelocityManager;
58   
59    import com.xpn.xwiki.XWiki;
60    import com.xpn.xwiki.XWikiContext;
61    import com.xpn.xwiki.doc.XWikiDocument;
62    import com.xpn.xwiki.objects.BaseObject;
63   
64    /**
65    * Default gadget reader, reads the gadgets from XWiki Objects attached to the current document.
66    *
67    * @version $Id: b9110ac39bdc42352d42b8433de1fb7dfae323e5 $
68    * @since 3.0M3
69    */
70    @Component
71    @Singleton
 
72    public class DefaultGadgetSource implements GadgetSource
73    {
74    /**
75    * The reference to the gadgets class, relative to the current wiki. <br>
76    * TODO: to make sure that this class exists before trying to read objects of this type.
77    */
78    private static final EntityReference GADGET_CLASS =
79    new EntityReference("GadgetClass", EntityType.DOCUMENT, new EntityReference("XWiki", EntityType.SPACE));
80   
81    /**
82    * The execution context, to grab XWiki context and access to documents.
83    */
84    @Inject
85    protected Execution execution;
86   
87    /**
88    * The current string reference resolver, to resolve the current document reference in the metadata of the block of
89    * the current macro.
90    */
91    @Inject
92    @Named("current")
93    protected DocumentReferenceResolver<String> currentReferenceResolver;
94   
95    /**
96    * The current entity reference resolver, to resolve the gadgets class reference.
97    */
98    @Inject
99    @Named("current")
100    protected DocumentReferenceResolver<EntityReference> currentReferenceEntityResolver;
101   
102    @Inject
103    @Named("local")
104    private EntityReferenceSerializer<String> localReferenceSerializer;
105   
106    /**
107    * Used to get the Velocity Engine and Velocity Context to use to evaluate the titles of the gadgets.
108    */
109    @Inject
110    private VelocityManager velocityManager;
111   
112    @Inject
113    private ContentExecutor<MacroTransformationContext> contentExecutor;
114   
115    /**
116    * Prepare the parser to parse the title and content of the gadget into blocks.
117    */
118    private ParserUtils parserUtils = new ParserUtils();
119   
 
120  1 toggle @Override
121    public List<Gadget> getGadgets(String source, MacroTransformationContext context) throws Exception
122    {
123    // use the passed source as a document reference
124  1 DocumentReference sourceDocRef = getSourceDocumentReference(source);
125  1 if (sourceDocRef == null) {
126  0 return new ArrayList<>();
127    }
128   
129    // get the current document, read the objects and turn that into gadgets
130  1 XWikiContext xContext = getXWikiContext();
131  1 XWiki xWiki = xContext.getWiki();
132  1 XWikiDocument sourceDoc = xWiki.getDocument(sourceDocRef, xContext);
133  1 DocumentReference gadgetsClass = currentReferenceEntityResolver.resolve(GADGET_CLASS);
134  1 List<BaseObject> gadgetObjects = sourceDoc.getXObjects(gadgetsClass);
135   
136  1 if (gadgetObjects == null) {
137  0 return new ArrayList<>();
138    }
139   
140  1 return prepareGadgets(gadgetObjects, sourceDoc.getSyntax(), context);
141    }
142   
143    /**
144    * Prepares a list of gadgets from a list of XWiki objects.
145    *
146    * @param objects the objects to read the gadgets from
147    * @param sourceSyntax the syntax of the source of the gadget objects
148    * @param context the macro transformation context, where the dashboard macro is being executed
149    * @return the list of gadgets, as read from the xwiki objects
150    * @throws Exception in case something happens while rendering the content in the objects
151    */
 
152  1 toggle private List<Gadget> prepareGadgets(List<BaseObject> objects, Syntax sourceSyntax,
153    MacroTransformationContext context) throws Exception
154    {
155  1 List<Gadget> gadgets = new ArrayList<>();
156   
157    // prepare velocity tools to render title
158  1 VelocityContext velocityContext = velocityManager.getVelocityContext();
159    // Use the Transformation id as the name passed to the Velocity Engine. This name is used internally
160    // by Velocity as a cache index key for caching macros.
161  1 String key = context.getTransformationContext().getId();
162  1 if (key == null) {
163  0 key = "unknown namespace";
164    }
165  1 VelocityEngine velocityEngine = velocityManager.getVelocityEngine();
166   
167  1 for (BaseObject xObject : objects) {
168  11 if (xObject == null) {
169  0 continue;
170    }
171    // get the data about the gadget from the object
172    // TODO: filter for dashboard name when that field will be in
173  11 String title = xObject.getStringValue("title");
174  11 String content = xObject.getLargeStringValue("content");
175  11 String position = xObject.getStringValue("position");
176  11 String id = xObject.getNumber() + "";
177   
178    // render title with velocity
179  11 StringWriter writer = new StringWriter();
180    // FIXME: the engine has an issue with $ and # as last character. To test and fix if it happens
181  11 velocityEngine.evaluate(velocityContext, writer, key, title);
182  11 String gadgetTitle = writer.toString();
183   
184    // parse both the title and content in the syntax of the transformation context
185  11 List<Block> titleBlocks =
186    renderGadgetProperty(gadgetTitle, sourceSyntax, xObject.getDocumentReference(), context);
187  11 List<Block> contentBlocks =
188    renderGadgetProperty(content, sourceSyntax, xObject.getDocumentReference(), context);
189   
190    // create a gadget will all these and add the gadget to the container of gadgets
191  11 Gadget gadget = new Gadget(id, titleBlocks, contentBlocks, position);
192  11 gadget.setTitleSource(title);
193  11 gadgets.add(gadget);
194    }
195  1 return gadgets;
196    }
197   
 
198  22 toggle private List<Block> renderGadgetProperty(String content, Syntax sourceSyntax, EntityReference sourceReference,
199    MacroTransformationContext context) throws MissingParserException, ParseException, ContentExecutorException
200    {
201  22 XDOM xdom = this.contentExecutor.execute(content, sourceSyntax, sourceReference, context);
202  22 List<Block> xdomBlocks = xdom.getChildren();
203  22 this.parserUtils.removeTopLevelParagraph(xdomBlocks);
204  22 return xdomBlocks;
205    }
206   
207    /**
208    * Resolves the source of the dashboard, based on the source parameter passed to this reader, handling the default
209    * behaviour when the source is missing.
210    *
211    * @param source the serialized reference of the document to read gadgets from
212    * @return the document reference to the current document (the document containing the macro, if it's an include)
213    */
 
214  1 toggle private DocumentReference getSourceDocumentReference(String source)
215    {
216    // if the source is empty or null, use current document
217  1 if (StringUtils.isEmpty(source)) {
218  1 return getXWikiContext().getDoc().getDocumentReference();
219    }
220   
221    // resolve the source as document reference, relative to current context
222  0 return currentReferenceResolver.resolve(source);
223    }
224   
225    /**
226    * Gets the xwiki context from the execution context.
227    *
228    * @return the xwiki context
229    */
 
230  3 toggle private XWikiContext getXWikiContext()
231    {
232  3 return (XWikiContext) execution.getContext().getProperty("xwikicontext");
233    }
234   
 
235  0 toggle @Override
236    public List<Block> getDashboardSourceMetadata(String source, MacroTransformationContext context)
237    {
238  0 DocumentReference sourceDoc = getSourceDocumentReference(source);
239  0 String classParameterName = "class";
240  0 GroupBlock metadataContainer = new GroupBlock();
241  0 metadataContainer.setParameter(classParameterName, DashboardMacro.METADATA);
242   
243    // generate anchors for the urls
244  0 XWikiContext xContext = getXWikiContext();
245  0 String editURL = xContext.getWiki().getURL(sourceDoc, "save", "", "", xContext);
246  0 LinkBlock editURLBlock =
247    new LinkBlock(Collections.<Block> emptyList(), new ResourceReference(editURL, ResourceType.URL), false);
248  0 editURLBlock.setParameter(classParameterName, DashboardMacro.EDIT_URL);
249  0 metadataContainer.addChild(editURLBlock);
250  0 String removeURL = xContext.getWiki().getURL(sourceDoc, "objectremove", "", "", xContext);
251  0 LinkBlock removeURLBlock =
252    new LinkBlock(Collections.<Block> emptyList(), new ResourceReference(removeURL, ResourceType.URL), false);
253  0 removeURLBlock.setParameter(classParameterName, DashboardMacro.REMOVE_URL);
254  0 metadataContainer.addChild(removeURLBlock);
255  0 String addURL = xContext.getWiki().getURL(sourceDoc, "objectadd", "", "", xContext);
256  0 LinkBlock addURLBlock =
257    new LinkBlock(Collections.<Block> emptyList(), new ResourceReference(addURL, ResourceType.URL), false);
258  0 addURLBlock.setParameter(classParameterName, DashboardMacro.ADD_URL);
259  0 metadataContainer.addChild(addURLBlock);
260   
261    // and create divs for the source metadata
262  0 GroupBlock sourcePageBlock = new GroupBlock();
263  0 sourcePageBlock.addChild(new WordBlock(sourceDoc.getName()));
264  0 sourcePageBlock.setParameter(classParameterName, DashboardMacro.SOURCE_PAGE);
265  0 metadataContainer.addChild(sourcePageBlock);
266  0 GroupBlock sourceSpaceBlock = new GroupBlock();
267    // Extract the full Space Reference (in order to support Nested Spaces) and set it in the XDOM
268  0 sourceSpaceBlock.addChild(new WordBlock(
269    this.localReferenceSerializer.serialize(sourceDoc.getLastSpaceReference())));
270  0 sourceSpaceBlock.setParameter(classParameterName, DashboardMacro.SOURCE_SPACE);
271  0 metadataContainer.addChild(sourceSpaceBlock);
272  0 GroupBlock sourceWikiBlock = new GroupBlock();
273  0 sourceWikiBlock.addChild(new WordBlock(sourceDoc.getWikiReference().getName()));
274  0 sourceWikiBlock.setParameter(classParameterName, DashboardMacro.SOURCE_WIKI);
275  0 metadataContainer.addChild(sourceWikiBlock);
276  0 String sourceURL = xContext.getWiki().getURL(sourceDoc, "view", "", "", xContext);
277  0 LinkBlock sourceURLBlock =
278    new LinkBlock(Collections.<Block> emptyList(), new ResourceReference(sourceURL, ResourceType.URL), false);
279  0 sourceURLBlock.setParameter(classParameterName, DashboardMacro.SOURCE_URL);
280  0 metadataContainer.addChild(sourceURLBlock);
281   
282  0 return Collections.<Block> singletonList(metadataContainer);
283    }
284   
 
285  1 toggle @Override
286    public boolean isEditing()
287    {
288    // get the XWiki context and look at the action. if it's "inline" or "edit", it's edit mode
289  1 XWikiContext context = getXWikiContext();
290  1 return "inline".equals(context.getAction()) || "edit".equals(context.getAction());
291    }
292    }