@Test public void transformNestedMacro() throws Exception { String expected = "beginDocument\n" + "beginMacroMarkerStandalone [testnestedmacro] []\n" + "beginMacroMarkerStandalone [testsimplemacro] []\n" + "beginParagraph\n" + "onWord [simplemacro0]\n" + "endParagraph\n" + "endMacroMarkerStandalone [testsimplemacro] []\n" + "endMacroMarkerStandalone [testnestedmacro] []\n" + "endDocument"; XDOM dom = new XDOM(Arrays.asList((Block) new MacroBlock("testnestedmacro", Collections.<String, String>emptyMap(), false))); this.transformation.transform(dom, new TransformationContext(dom, Syntax.XWIKI_2_0)); WikiPrinter printer = new DefaultWikiPrinter(); BlockRenderer eventBlockRenderer = this.componentManager.getInstance(BlockRenderer.class, Syntax.EVENT_1_0.toIdString()); eventBlockRenderer.render(dom, printer); Assert.assertEquals(expected, printer.toString()); }
@Override public void transform(Block rootBlock, TransformationContext context) throws TransformationException { MacroTransformationContext macroContext = new MacroTransformationContext(context); macroContext.setTransformation(this); for (int recursions = 0; recursions < this.maxRecursions;) { PriorityMacroBlockMatcher priorityMacroBlockMatcher = new PriorityMacroBlockMatcher(context.getSyntax()); rootBlock.getFirstBlock(priorityMacroBlockMatcher, Block.Axes.DESCENDANT); if (priorityMacroBlockMatcher.getErrors() != null) { for (MacroLookupExceptionElement error : priorityMacroBlockMatcher.getErrors()) { if (error.getException() instanceof MacroNotFoundException) { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Unknown macro: %s.", error.getMacroBlock().getId()), String.format( "The \"%s\" macro is not in the list of registered macros. Verify the spelling or " + "contact your administrator.", error.getMacroBlock().getId())); } else { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Invalid macro: %s", error.getMacroBlock().getId()), error.getException()); } } } MacroBlock macroBlock = priorityMacroBlockMatcher.getBlock(); if (macroBlock == null) { return; } Macro<?> macro = priorityMacroBlockMatcher.getBlockMacro(); boolean incrementRecursions = macroBlock.getParent() instanceof MacroMarkerBlock; List<Block> newBlocks; try { if (macroBlock.isInline()) { macroContext.setInline(true); if (!macro.supportsInlineMode()) { this.macroErrorManager.generateError(macroBlock, String.format( "The [%s] macro is a standalone macro and it cannot be used inline", macroBlock.getId()), "This macro generates standalone content. As a consequence you need to make sure to use a " + "syntax that separates your macro from the content before and after it so that it's on a " + "line by itself. For example in XWiki Syntax 2.0+ this means having 2 newline characters " + "(a.k.a line breaks) separating your macro from the content before and after it."); continue; } } else { macroContext.setInline(false); } macroContext.setCurrentMacroBlock(macroBlock); ((MutableRenderingContext) this.renderingContext).setCurrentBlock(macroBlock); Object macroParameters = macro.getDescriptor().getParametersBeanClass().newInstance(); try { this.beanManager.populate(macroParameters, macroBlock.getParameters()); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Invalid macro parameters used for the \"%s\" macro", macroBlock.getId()), e); continue; } newBlocks = ((Macro) macro).execute(macroParameters, macroBlock.getContent(), macroContext); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Failed to execute the [%s] macro", macroBlock.getId()), e); continue; } finally { ((MutableRenderingContext) this.renderingContext).setCurrentBlock(null); } Block resultBlock = wrapInMacroMarker(macroBlock, newBlocks); macroBlock.getParent().replaceChild(resultBlock, macroBlock); if (incrementRecursions) { ++recursions; } } }
MacroTransformation extends AbstractTransformation implements Initializable { @Override public void transform(Block rootBlock, TransformationContext context) throws TransformationException { MacroTransformationContext macroContext = new MacroTransformationContext(context); macroContext.setTransformation(this); for (int recursions = 0; recursions < this.maxRecursions;) { PriorityMacroBlockMatcher priorityMacroBlockMatcher = new PriorityMacroBlockMatcher(context.getSyntax()); rootBlock.getFirstBlock(priorityMacroBlockMatcher, Block.Axes.DESCENDANT); if (priorityMacroBlockMatcher.getErrors() != null) { for (MacroLookupExceptionElement error : priorityMacroBlockMatcher.getErrors()) { if (error.getException() instanceof MacroNotFoundException) { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Unknown macro: %s.", error.getMacroBlock().getId()), String.format( "The \"%s\" macro is not in the list of registered macros. Verify the spelling or " + "contact your administrator.", error.getMacroBlock().getId())); } else { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Invalid macro: %s", error.getMacroBlock().getId()), error.getException()); } } } MacroBlock macroBlock = priorityMacroBlockMatcher.getBlock(); if (macroBlock == null) { return; } Macro<?> macro = priorityMacroBlockMatcher.getBlockMacro(); boolean incrementRecursions = macroBlock.getParent() instanceof MacroMarkerBlock; List<Block> newBlocks; try { if (macroBlock.isInline()) { macroContext.setInline(true); if (!macro.supportsInlineMode()) { this.macroErrorManager.generateError(macroBlock, String.format( "The [%s] macro is a standalone macro and it cannot be used inline", macroBlock.getId()), "This macro generates standalone content. As a consequence you need to make sure to use a " + "syntax that separates your macro from the content before and after it so that it's on a " + "line by itself. For example in XWiki Syntax 2.0+ this means having 2 newline characters " + "(a.k.a line breaks) separating your macro from the content before and after it."); continue; } } else { macroContext.setInline(false); } macroContext.setCurrentMacroBlock(macroBlock); ((MutableRenderingContext) this.renderingContext).setCurrentBlock(macroBlock); Object macroParameters = macro.getDescriptor().getParametersBeanClass().newInstance(); try { this.beanManager.populate(macroParameters, macroBlock.getParameters()); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Invalid macro parameters used for the \"%s\" macro", macroBlock.getId()), e); continue; } newBlocks = ((Macro) macro).execute(macroParameters, macroBlock.getContent(), macroContext); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Failed to execute the [%s] macro", macroBlock.getId()), e); continue; } finally { ((MutableRenderingContext) this.renderingContext).setCurrentBlock(null); } Block resultBlock = wrapInMacroMarker(macroBlock, newBlocks); macroBlock.getParent().replaceChild(resultBlock, macroBlock); if (incrementRecursions) { ++recursions; } } } }
MacroTransformation extends AbstractTransformation implements Initializable { @Override public void transform(Block rootBlock, TransformationContext context) throws TransformationException { MacroTransformationContext macroContext = new MacroTransformationContext(context); macroContext.setTransformation(this); for (int recursions = 0; recursions < this.maxRecursions;) { PriorityMacroBlockMatcher priorityMacroBlockMatcher = new PriorityMacroBlockMatcher(context.getSyntax()); rootBlock.getFirstBlock(priorityMacroBlockMatcher, Block.Axes.DESCENDANT); if (priorityMacroBlockMatcher.getErrors() != null) { for (MacroLookupExceptionElement error : priorityMacroBlockMatcher.getErrors()) { if (error.getException() instanceof MacroNotFoundException) { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Unknown macro: %s.", error.getMacroBlock().getId()), String.format( "The \"%s\" macro is not in the list of registered macros. Verify the spelling or " + "contact your administrator.", error.getMacroBlock().getId())); } else { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Invalid macro: %s", error.getMacroBlock().getId()), error.getException()); } } } MacroBlock macroBlock = priorityMacroBlockMatcher.getBlock(); if (macroBlock == null) { return; } Macro<?> macro = priorityMacroBlockMatcher.getBlockMacro(); boolean incrementRecursions = macroBlock.getParent() instanceof MacroMarkerBlock; List<Block> newBlocks; try { if (macroBlock.isInline()) { macroContext.setInline(true); if (!macro.supportsInlineMode()) { this.macroErrorManager.generateError(macroBlock, String.format( "The [%s] macro is a standalone macro and it cannot be used inline", macroBlock.getId()), "This macro generates standalone content. As a consequence you need to make sure to use a " + "syntax that separates your macro from the content before and after it so that it's on a " + "line by itself. For example in XWiki Syntax 2.0+ this means having 2 newline characters " + "(a.k.a line breaks) separating your macro from the content before and after it."); continue; } } else { macroContext.setInline(false); } macroContext.setCurrentMacroBlock(macroBlock); ((MutableRenderingContext) this.renderingContext).setCurrentBlock(macroBlock); Object macroParameters = macro.getDescriptor().getParametersBeanClass().newInstance(); try { this.beanManager.populate(macroParameters, macroBlock.getParameters()); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Invalid macro parameters used for the \"%s\" macro", macroBlock.getId()), e); continue; } newBlocks = ((Macro) macro).execute(macroParameters, macroBlock.getContent(), macroContext); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Failed to execute the [%s] macro", macroBlock.getId()), e); continue; } finally { ((MutableRenderingContext) this.renderingContext).setCurrentBlock(null); } Block resultBlock = wrapInMacroMarker(macroBlock, newBlocks); macroBlock.getParent().replaceChild(resultBlock, macroBlock); if (incrementRecursions) { ++recursions; } } }  }
MacroTransformation extends AbstractTransformation implements Initializable { @Override public void transform(Block rootBlock, TransformationContext context) throws TransformationException { MacroTransformationContext macroContext = new MacroTransformationContext(context); macroContext.setTransformation(this); for (int recursions = 0; recursions < this.maxRecursions;) { PriorityMacroBlockMatcher priorityMacroBlockMatcher = new PriorityMacroBlockMatcher(context.getSyntax()); rootBlock.getFirstBlock(priorityMacroBlockMatcher, Block.Axes.DESCENDANT); if (priorityMacroBlockMatcher.getErrors() != null) { for (MacroLookupExceptionElement error : priorityMacroBlockMatcher.getErrors()) { if (error.getException() instanceof MacroNotFoundException) { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Unknown macro: %s.", error.getMacroBlock().getId()), String.format( "The \"%s\" macro is not in the list of registered macros. Verify the spelling or " + "contact your administrator.", error.getMacroBlock().getId())); } else { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Invalid macro: %s", error.getMacroBlock().getId()), error.getException()); } } } MacroBlock macroBlock = priorityMacroBlockMatcher.getBlock(); if (macroBlock == null) { return; } Macro<?> macro = priorityMacroBlockMatcher.getBlockMacro(); boolean incrementRecursions = macroBlock.getParent() instanceof MacroMarkerBlock; List<Block> newBlocks; try { if (macroBlock.isInline()) { macroContext.setInline(true); if (!macro.supportsInlineMode()) { this.macroErrorManager.generateError(macroBlock, String.format( "The [%s] macro is a standalone macro and it cannot be used inline", macroBlock.getId()), "This macro generates standalone content. As a consequence you need to make sure to use a " + "syntax that separates your macro from the content before and after it so that it's on a " + "line by itself. For example in XWiki Syntax 2.0+ this means having 2 newline characters " + "(a.k.a line breaks) separating your macro from the content before and after it."); continue; } } else { macroContext.setInline(false); } macroContext.setCurrentMacroBlock(macroBlock); ((MutableRenderingContext) this.renderingContext).setCurrentBlock(macroBlock); Object macroParameters = macro.getDescriptor().getParametersBeanClass().newInstance(); try { this.beanManager.populate(macroParameters, macroBlock.getParameters()); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Invalid macro parameters used for the \"%s\" macro", macroBlock.getId()), e); continue; } newBlocks = ((Macro) macro).execute(macroParameters, macroBlock.getContent(), macroContext); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Failed to execute the [%s] macro", macroBlock.getId()), e); continue; } finally { ((MutableRenderingContext) this.renderingContext).setCurrentBlock(null); } Block resultBlock = wrapInMacroMarker(macroBlock, newBlocks); macroBlock.getParent().replaceChild(resultBlock, macroBlock); if (incrementRecursions) { ++recursions; } } }  @Override void initialize(); @Override int getPriority(); @Override void transform(Block rootBlock, TransformationContext context); void setMaxRecursions(int maxRecursions); }
MacroTransformation extends AbstractTransformation implements Initializable { @Override public void transform(Block rootBlock, TransformationContext context) throws TransformationException { MacroTransformationContext macroContext = new MacroTransformationContext(context); macroContext.setTransformation(this); for (int recursions = 0; recursions < this.maxRecursions;) { PriorityMacroBlockMatcher priorityMacroBlockMatcher = new PriorityMacroBlockMatcher(context.getSyntax()); rootBlock.getFirstBlock(priorityMacroBlockMatcher, Block.Axes.DESCENDANT); if (priorityMacroBlockMatcher.getErrors() != null) { for (MacroLookupExceptionElement error : priorityMacroBlockMatcher.getErrors()) { if (error.getException() instanceof MacroNotFoundException) { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Unknown macro: %s.", error.getMacroBlock().getId()), String.format( "The \"%s\" macro is not in the list of registered macros. Verify the spelling or " + "contact your administrator.", error.getMacroBlock().getId())); } else { this.macroErrorManager.generateError(error.getMacroBlock(), String.format("Invalid macro: %s", error.getMacroBlock().getId()), error.getException()); } } } MacroBlock macroBlock = priorityMacroBlockMatcher.getBlock(); if (macroBlock == null) { return; } Macro<?> macro = priorityMacroBlockMatcher.getBlockMacro(); boolean incrementRecursions = macroBlock.getParent() instanceof MacroMarkerBlock; List<Block> newBlocks; try { if (macroBlock.isInline()) { macroContext.setInline(true); if (!macro.supportsInlineMode()) { this.macroErrorManager.generateError(macroBlock, String.format( "The [%s] macro is a standalone macro and it cannot be used inline", macroBlock.getId()), "This macro generates standalone content. As a consequence you need to make sure to use a " + "syntax that separates your macro from the content before and after it so that it's on a " + "line by itself. For example in XWiki Syntax 2.0+ this means having 2 newline characters " + "(a.k.a line breaks) separating your macro from the content before and after it."); continue; } } else { macroContext.setInline(false); } macroContext.setCurrentMacroBlock(macroBlock); ((MutableRenderingContext) this.renderingContext).setCurrentBlock(macroBlock); Object macroParameters = macro.getDescriptor().getParametersBeanClass().newInstance(); try { this.beanManager.populate(macroParameters, macroBlock.getParameters()); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Invalid macro parameters used for the \"%s\" macro", macroBlock.getId()), e); continue; } newBlocks = ((Macro) macro).execute(macroParameters, macroBlock.getContent(), macroContext); } catch (Throwable e) { this.macroErrorManager.generateError(macroBlock, String.format("Failed to execute the [%s] macro", macroBlock.getId()), e); continue; } finally { ((MutableRenderingContext) this.renderingContext).setCurrentBlock(null); } Block resultBlock = wrapInMacroMarker(macroBlock, newBlocks); macroBlock.getParent().replaceChild(resultBlock, macroBlock); if (incrementRecursions) { ++recursions; } } }  @Override void initialize(); @Override int getPriority(); @Override void transform(Block rootBlock, TransformationContext context); void setMaxRecursions(int maxRecursions);  }