Add logging support for converters
MODIFY
asciidoctorj-api/src/main/java/org/asciidoctor/converter/AbstractConverter.java
asciidoctorj-api/src/main/java/org/asciidoctor/converter/AbstractConverter.java
package org.asciidoctor.converter;
+import org.asciidoctor.log.LogHandler;
+import org.asciidoctor.log.LogRecord;
+import org.asciidoctor.log.Logging;
+
import java.util.Map;
/**
@@ -8,7 +12,7 @@ import java.util.Map;
* <p>For converters producing string output consider extending the {@link StringConverter} class.
* @param <T> The type of result this converter produces, e.g. {@link String}.
*/
-public abstract class AbstractConverter<T> implements Converter<T>, OutputFormatWriter<T> {
+public abstract class AbstractConverter<T> implements Converter<T>, OutputFormatWriter<T>, Logging, LogHandler {
private String backend;
@@ -16,6 +20,8 @@ public abstract class AbstractConverter<T> implements Converter<T>, OutputFormat
private String outfilesuffix = null;
+ private LogHandler logHandler;
+
public AbstractConverter(String backend, Map<String, Object> opts) {
this.backend = backend;
this.options = opts;
@@ -40,4 +46,15 @@ public abstract class AbstractConverter<T> implements Converter<T>, OutputFormat
this.outfilesuffix = outfilesuffix;
}
+ @Override
+ public void log(LogRecord logRecord) {
+ if (logHandler != null) {
+ logHandler.log(logRecord);
+ }
+ }
+
+ @Override
+ public void setLogHandler(LogHandler logHandler) {
+ this.logHandler = logHandler;
+ }
}

ADD
asciidoctorj-api/src/main/java/org/asciidoctor/log/Logging.java
+package org.asciidoctor.log;
+
+public interface Logging {
+
+ void setLogHandler(LogHandler logHandler);
+
+}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/converter/internal/ConverterProxy.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/converter/internal/ConverterProxy.java
package org.asciidoctor.jruby.converter.internal;
import org.asciidoctor.ast.ContentNode;
-import org.asciidoctor.jruby.ast.impl.NodeConverter;
import org.asciidoctor.converter.Converter;
import org.asciidoctor.converter.ConverterFor;
import org.asciidoctor.converter.OutputFormatWriter;
+import org.asciidoctor.jruby.ast.impl.NodeConverter;
+import org.asciidoctor.jruby.internal.JRubyAsciidoctor;
import org.asciidoctor.jruby.internal.RubyHashMapDecorator;
import org.asciidoctor.jruby.internal.RubyHashUtil;
import org.asciidoctor.jruby.internal.RubyOutputStreamWrapper;
+import org.asciidoctor.log.Logging;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyHash;
@@ -35,15 +37,17 @@ import java.util.Map;
public class ConverterProxy<T> extends RubyObject {
protected static final String METHOD_NAME_INITIALIZE = "initialize";
+ private final JRubyAsciidoctor asciidoctor;
private T output;
- public static <U, T extends Converter<U> & OutputFormatWriter<U>> RubyClass register(Ruby rubyRuntime, final Class<T> converterClass) {
+ public static <U, T extends Converter<U> & OutputFormatWriter<U>> RubyClass register(JRubyAsciidoctor asciidoctor, final Class<T> converterClass) {
+ Ruby rubyRuntime = asciidoctor.getRubyRuntime();
RubyModule module = rubyRuntime.defineModule(getModuleName(converterClass));
RubyClass clazz = module.defineClassUnder(
converterClass.getSimpleName(),
rubyRuntime.getObject(),
- new ConverterProxy.Allocator(converterClass));
+ new ConverterProxy.Allocator(converterClass, asciidoctor));
includeModule(clazz, "Asciidoctor", "Converter");
includeModule(clazz, "Asciidoctor", "Converter", "BackendTraits");
@@ -59,13 +63,15 @@ public class ConverterProxy<T> extends RubyObject {
public static class Allocator implements ObjectAllocator {
private final Class<? extends Converter> converterClass;
+ private final JRubyAsciidoctor asciidoctor;
- public Allocator(Class<? extends Converter> converterClass) {
+ public Allocator(Class<? extends Converter> converterClass, JRubyAsciidoctor asciidoctor) {
this.converterClass = converterClass;
+ this.asciidoctor = asciidoctor;
}
@Override
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
- return new ConverterProxy(runtime, rubyClass, converterClass);
+ return new ConverterProxy(runtime, rubyClass, converterClass, asciidoctor);
}
public Class<? extends Converter> getConverterClass() {
@@ -77,9 +83,10 @@ public class ConverterProxy<T> extends RubyObject {
private Converter<T> delegate;
- public ConverterProxy(Ruby runtime, RubyClass metaClass, Class<? extends Converter> converterClass) {
+ public ConverterProxy(Ruby runtime, RubyClass metaClass, Class<? extends Converter> converterClass, JRubyAsciidoctor asciidoctor) {
super(runtime, metaClass);
this.converterClass = converterClass;
+ this.asciidoctor = asciidoctor;
}
@JRubyMethod(required = 1, optional = 1)
@@ -92,7 +99,9 @@ public class ConverterProxy<T> extends RubyObject {
backend,
args.length < 2 ? Collections.emptyMap() : new RubyHashMapDecorator((RubyHash) args[1])
);
-
+ if (this.delegate instanceof Logging) {
+ ((Logging) this.delegate).setLogHandler(asciidoctor);
+ }
// Initialize the Ruby part and pass in the config options
RubyHash options = RubyHashUtil.convertMapToRubyHashWithSymbols(context.getRuntime(), this.delegate.getOptions());
Helpers.invokeSuper(context, this, getMetaClass(), METHOD_NAME_INITIALIZE, new IRubyObject[]{args[0], options}, Block.NULL_BLOCK);

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java
@@ -233,7 +233,7 @@ public class JRubyAsciidoctor implements AsciidoctorJRuby, LogHandler {
@Override
public JavaConverterRegistry javaConverterRegistry() {
- return new JavaConverterRegistryImpl(rubyRuntime);
+ return new JavaConverterRegistryImpl(this);
}
@Override

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JavaConverterRegistryImpl.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JavaConverterRegistryImpl.java
@@ -17,14 +17,17 @@ public class JavaConverterRegistryImpl implements JavaConverterRegistry {
private Ruby rubyRuntime;
- public JavaConverterRegistryImpl(Ruby rubyRuntime) {
- this.rubyRuntime = rubyRuntime;
+ private JRubyAsciidoctor asciidoctor;
+
+ public JavaConverterRegistryImpl(JRubyAsciidoctor asciidoctor) {
+ this.asciidoctor = asciidoctor;
+ this.rubyRuntime = asciidoctor.getRubyRuntime();
}
@Override
public <U, T extends Converter<U> & OutputFormatWriter<U>> void register(final Class<T> converterClass, String... backends) {
- RubyClass clazz = ConverterProxy.register(rubyRuntime, converterClass);
+ RubyClass clazz = ConverterProxy.register(asciidoctor, converterClass);
ConverterFor converterForAnnotation = converterClass.getAnnotation(ConverterFor.class);
if (converterForAnnotation != null) {

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/converter/TextConverter.java
asciidoctorj-core/src/test/java/org/asciidoctor/converter/TextConverter.java
@@ -6,6 +6,8 @@ import org.asciidoctor.ast.Document;
import org.asciidoctor.ast.ListItem;
import org.asciidoctor.ast.List;
import org.asciidoctor.ast.Section;
+import org.asciidoctor.log.LogRecord;
+import org.asciidoctor.log.Severity;
import java.util.Map;
@@ -23,11 +25,13 @@ public class TextConverter extends StringConverter {
@Override
public String convert(ContentNode node, String transform, Map<Object, Object> o) {
+
if (transform == null) {
transform = node.getNodeName();
}
if (node instanceof Document) {
+ log(new LogRecord(Severity.INFO, "Now we're logging"));
Document document = (Document) node;
return (String) document.getContent();
} else if (node instanceof Section) {

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/converter/WhenConverterIsRegistered.java
asciidoctorj-core/src/test/java/org/asciidoctor/converter/WhenConverterIsRegistered.java
package org.asciidoctor.converter;
import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.MemoryLogHandler;
import org.asciidoctor.OptionsBuilder;
import org.asciidoctor.SafeMode;
+import org.asciidoctor.arquillian.api.Unshared;
import org.asciidoctor.jruby.internal.JRubyAsciidoctor;
import org.asciidoctor.util.ClasspathResources;
-import org.asciidoctor.arquillian.api.Unshared;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.junit.After;
@@ -16,9 +17,11 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.logging.Logger;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@@ -76,6 +79,29 @@ public class WhenConverterIsRegistered {
assertThat(result, is("Dummy"));
}
+ private MemoryLogHandler registerMemoryLogHandler() {
+ final Logger logger = Logger.getLogger("asciidoctor");
+ final MemoryLogHandler handler = new MemoryLogHandler();
+ logger.addHandler(handler);
+ return handler;
+ }
+
+ @Test
+ public void shouldBeAbleToLog() {
+ MemoryLogHandler handler = registerMemoryLogHandler();
+ try {
+ asciidoctor.javaConverterRegistry().register(TextConverter.class);
+
+ String result = asciidoctor.convert("== Hello\n\nWorld!\n\n- a\n- b", OptionsBuilder.options().backend(TextConverter.DEFAULT_FORMAT));
+
+ assertThat(handler.getLogRecords(), hasSize(1));
+ assertThat(handler.getLogRecords().get(0).getMessage(), is("Now we're logging"));
+ } finally {
+ final Logger logger = Logger.getLogger("asciidoctor");
+ logger.removeHandler(handler);
+ }
+ }
+
@Test
public void shouldReturnConverterRegisteredWithAnnotation() {

Add logging support for converters