/* * Copyright (C) 2010 eXo Platform SAS. * * 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.wikbook.xwiki; import org.wikbook.core.Utils; import org.wikbook.core.WikbookException; import org.xwiki.component.embed.EmbeddableComponentManager; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.rendering.block.Block; import org.xwiki.rendering.block.HeaderBlock; import org.xwiki.rendering.block.MacroBlock; import org.xwiki.rendering.block.SectionBlock; import org.xwiki.rendering.block.VerbatimBlock; import org.xwiki.rendering.block.WordBlock; import org.xwiki.rendering.block.XDOM; import org.xwiki.rendering.listener.HeaderLevel; import org.xwiki.rendering.parser.ParseException; import org.xwiki.rendering.parser.Parser; import org.xwiki.rendering.renderer.BlockRenderer; import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter; import org.xwiki.rendering.renderer.printer.WikiPrinter; import org.xwiki.rendering.syntax.Syntax; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> * @version $Revision$ */ class WikiLoader { /** . */ private static final Map<String, PatternFilter> ESCAPE_FILTER_MAP = new HashMap<String, PatternFilter>() { { put(Syntax.XWIKI_2_0.toIdString(), new PatternFilter.Escape("{{{", "}}}")); put(Syntax.CONFLUENCE_1_0.toIdString(), new PatternFilter.Escape("{{{", "}}}")); } }; /** . */ private final AbstractXDOMDocbookBuilderContext context; /** . */ private final EmbeddableComponentManager ecm; /** . */ private final LinkedList<String> resourceIdStack; public WikiLoader(AbstractXDOMDocbookBuilderContext context) throws WikbookException { EmbeddableComponentManager ecm = new EmbeddableComponentManager(); ecm.initialize(Thread.currentThread().getContextClassLoader()); // this.context = context; this.ecm = ecm; this.resourceIdStack = new LinkedList<String>(); } public Block load(Reader reader, String syntaxId) throws WikbookException { return load(reader, syntaxId, 0); } private Block load(String id, String syntaxId, int baseLevel) throws WikbookException { try { // Obtain reader Reader reader = context.read(resourceIdStack, id); // Push resource id resourceIdStack.addLast(id); // Perform inclusion try { return load(reader, syntaxId, baseLevel); } finally { // Pop resource id resourceIdStack.removeLast(); } } catch (IOException e) { throw new WikbookException(e); } } private Block load(Reader reader, String syntaxId, int baseLevel) throws WikbookException { if (syntaxId == null) { throw new NullPointerException("No null syntax accepted"); } // try { // Load the text String s = Utils.read(reader); // Filter escapes PatternFilter filter = ESCAPE_FILTER_MAP.get(syntaxId); if (filter != null) { s = filter.filter(s); } // Filter properties s = new PatternFilter.Properties() { @Override protected String resolveProperty(String propertyname) { return context.getProperty(propertyname); } }.filter(s); // XDOM xdom; if ("verbatim".equals(syntaxId)) { xdom = new XDOM(new ArrayList<Block>()); xdom.addChild(new VerbatimBlock(s, false)); } else { // Get parser Parser parser = ecm.lookup(Parser.class, syntaxId); // Parse xdom = parser.parse(new StringReader(s)); // Replace all headers if (baseLevel > 0) { for (HeaderBlock header : xdom.getChildrenByType(HeaderBlock.class, true)) { int l = baseLevel + header.getLevel().getAsInt(); HeaderBlock nheader = new HeaderBlock( header.getChildren(), HeaderLevel.parseInt(l), header.getParameters(), header.getId() ); header.getParent().replaceChild(nheader, header); } } // List<Substitution> substitutions = visit(xdom, baseLevel, syntaxId); // if (substitutions.size() > 0) { for (Substitution substitution : substitutions) { substitution.src.getParent().replaceChild(substitution.dst, substitution.src); } WikiPrinter printer = new DefaultWikiPrinter(); BlockRenderer substitutionRenderer = ecm.lookup(BlockRenderer.class, Syntax.XWIKI_2_0.toIdString()); substitutionRenderer.render(xdom, printer); Parser substitutionParser = ecm.lookup(Parser.class, Syntax.XWIKI_2_0.toIdString()); xdom = substitutionParser.parse(new StringReader(printer.toString())); } } // Returns include block instead of XDOM return new IncludeBlock(syntaxId, xdom.getChildren()); } catch (IOException e) { throw new WikbookException(e); } catch (ComponentLookupException e) { throw new WikbookException(e); } catch (ParseException e) { throw new WikbookException(e); } } /** * Visit a block and returns the list of substitutions that must be performed in the visited block. The returned list * can be safely modified. * * @param block the block to visit * @param currentSyntaxId the current syntax is * @return the substitution list */ private List<Substitution> visit(Block block, String currentSyntaxId) { return visit(block, 0, currentSyntaxId); } private List<Substitution> visit(Block block, int level, String currentSyntaxId) { if (block instanceof MacroBlock) { MacroBlock macro = (MacroBlock)block; String id = macro.getId(); if ("include".equals(id)) { String includedId = macro.getParameter("document"); String syntaxId = macro.getParameter("syntax"); if (syntaxId == null) { syntaxId = currentSyntaxId; } LinkedList<Substitution> list = new LinkedList<Substitution>(); list.add(new Substitution(block, load(includedId, syntaxId, level))); return list; } else if (id.startsWith("property.")) { String name = id.substring("property.".length()); if (name != null) { String value = context.getProperty(name); if (value != null) { LinkedList<Substitution> list = new LinkedList<Substitution>(); list.add(new Substitution(block, new WordBlock(value))); return list; } } } } else if (block instanceof SectionBlock) { level++; } // List<Substitution> substitutions = new LinkedList<Substitution>(); for (Block child : block.getChildren()) { List<Substitution> childSubstitutions = visit(child, level, currentSyntaxId); if (childSubstitutions.size() > 0) { substitutions.addAll(childSubstitutions); } } // return substitutions; } }