/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.uiextension.internal;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.wiki.WikiComponentException;
import org.xwiki.component.wiki.internal.bridge.ContentParser;
import org.xwiki.context.Execution;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.rendering.block.CompositeBlock;
import org.xwiki.rendering.block.XDOM;
import org.xwiki.rendering.internal.transformation.MutableRenderingContext;
import org.xwiki.rendering.transformation.RenderingContext;
import org.xwiki.rendering.transformation.Transformation;
import org.xwiki.rendering.transformation.TransformationContext;
import org.xwiki.rendering.transformation.TransformationException;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
/**
* Parse the UI Extension content as an XDOM, cache it and when asked, apply Rendering Transformations on the XDOM
* and return the modified XDOM.
*
* @version $Id: 1652d1244a31657093942f10316cf6b286a5b87f $
* @since 5.0M1
*/
public class WikiUIExtensionRenderer
{
/**
* The logger to log.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(WikiUIExtensionRenderer.class);
/**
* Role hint of the UI extension this renderer is bound to.
*/
private final String roleHint;
/**
* Used to update the rendering context.
*/
private final RenderingContext renderingContext;
/**
* Used to transform the macros within the extension content.
*/
private final Transformation macroTransformation;
/**
* Used to retrieve the XWiki context.
*/
private final Execution execution;
/**
* The xdom from the parsed content, we keep it in order to parse it only once.
*/
private final XDOM xdom;
/**
* Reference to the document holding the extension.
*/
private final DocumentReference documentReference;
/**
* Default constructor.
*
* @param roleHint hint of the UI extension this renderer is bound to
* @param content content to render
* @param documentReference a reference to the document holding the extension
* @param cm the component manager
* @throws WikiComponentException if some required components can't be found in the Component Manager
*/
public WikiUIExtensionRenderer(String roleHint, String content, DocumentReference documentReference,
ComponentManager cm) throws WikiComponentException
{
this.roleHint = roleHint;
try {
this.execution = cm.getInstance(Execution.class);
this.renderingContext = cm.getInstance(RenderingContext.class);
this.macroTransformation = cm.<Transformation>getInstance(Transformation.class, "macro");
ContentParser contentParser = cm.getInstance(ContentParser.class);
XWikiDocument xdoc = getXWikiContext().getWiki().getDocument(documentReference, getXWikiContext());
this.xdom = contentParser.parse(content, xdoc.getSyntax(), documentReference);
this.documentReference = documentReference;
} catch (ComponentLookupException ex) {
throw new WikiComponentException(
"Failed to get an instance for a component role required by Wiki Components.", ex);
} catch (XWikiException e) {
throw new WikiComponentException(String.format(
"Failed to retrieve document [%s]", documentReference), e);
}
}
/**
* @return the rendered content of the extension
*/
public CompositeBlock execute()
{
// We need to clone the xdom to avoid transforming the original and make it useless after the first
// transformation
XDOM transformedXDOM = xdom.clone();
// Perform macro transformations.
try {
// Get the document holding the UIX and put it in the UIX context
XWikiDocument xdoc = getXWikiContext().getWiki().getDocument(documentReference, getXWikiContext());
Map<String, Object> uixContext = new HashMap<String, Object>();
uixContext.put(WikiUIExtension.CONTEXT_UIX_DOC_KEY, xdoc.newDocument(getXWikiContext()));
// Put the UIX context in the XWiki context
getXWikiContext().put(WikiUIExtension.CONTEXT_UIX_KEY, uixContext);
// Transform the macros
TransformationContext transformationContext = new TransformationContext(xdom, xdoc.getSyntax());
transformationContext.setId(roleHint);
((MutableRenderingContext) renderingContext).transformInContext(macroTransformation,
transformationContext, transformedXDOM);
} catch (TransformationException e) {
LOGGER.warn("Error while executing wiki component macro transformation for extension [{}]", roleHint);
} catch (XWikiException ex) {
LOGGER.warn("Failed to retrieve document [{}]", documentReference);
}
return new CompositeBlock(transformedXDOM.getChildren());
}
/**
* Utility method for accessing XWikiContext.
*
* @return the XWikiContext.
*/
private XWikiContext getXWikiContext()
{
return (XWikiContext) this.execution.getContext().getProperty("xwikicontext");
}
}