Skip to content

Commit

Permalink
Fixes asciidoctor#1158. Avoid concurrent initialization of Ruby wrapp…
Browse files Browse the repository at this point in the history
…er class when converting to stream.
  • Loading branch information
robertpanzer committed Apr 9, 2023
1 parent 098cfda commit 1ef4aed
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Improvement::
* Upgrade to asciidoctorj-diagram 2.2.4 (#1140)
* Upgrade to jruby 9.3.10.0 (#1138) (@alexlevinfr)

Bug Fixes::

* Fix ConcurrentModificationException when converting to stream concurrently (#1158) (@rocketraman)

Build / Infrastructure::

* Replace use of deprecated 'numbered' attribute by 'sectnums' (#1127) (@abelsromero)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.RubyExtensionRegistry;
import org.asciidoctor.jruby.AsciidoctorJRuby;
import org.asciidoctor.jruby.DirectoryWalker;
import org.asciidoctor.jruby.ast.impl.AuthorImpl;
import org.asciidoctor.jruby.ast.impl.DocumentHeaderImpl;
import org.asciidoctor.jruby.ast.impl.NodeConverter;
import org.asciidoctor.jruby.converter.internal.ConverterRegistryExecutor;
Expand All @@ -23,13 +21,29 @@
import org.asciidoctor.log.LogHandler;
import org.asciidoctor.log.LogRecord;
import org.asciidoctor.syntaxhighlighter.SyntaxHighlighterRegistry;
import org.jruby.*;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyHash;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;

import java.io.*;
import java.util.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

public class JRubyAsciidoctor implements AsciidoctorJRuby, LogHandler {
Expand Down Expand Up @@ -60,6 +74,7 @@ private JRubyAsciidoctor(final Ruby rubyRuntime) {

this.rubyGemsPreloader = new RubyGemsPreloader(this.rubyRuntime);
this.logHandlers.add(new JULLogHandler());
RubyOutputStreamWrapper.getOrCreateOutputStreamWrapperClass(this.rubyRuntime);
}

public static JRubyAsciidoctor create() {
Expand Down Expand Up @@ -184,7 +199,6 @@ public DocumentHeader readDocumentHeader(File file) {
return toDocumentHeader(document);
}

@SuppressWarnings("unchecked")
@Override
public DocumentHeader readDocumentHeader(String content) {

Expand Down Expand Up @@ -217,10 +231,6 @@ private List<String> convertAllFiles(Map<String, Object> options, final Iterable
return asciidoctorContent;
}

private List<File> scanForAsciiDocFiles(DirectoryWalker directoryWalker) {
return directoryWalker.scan();
}

@Override
public void requireLibrary(String... library) {
requireLibraries(Arrays.asList(library));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

Expand All @@ -25,7 +24,7 @@ public class RubyOutputStreamWrapper extends RubyObject {

public static IRubyObject wrap(final Ruby rubyRuntime, final OutputStream out) {

final RubyClass rubyClass = getOrCreateOutputStreamWrapperClass(rubyRuntime);
final RubyClass rubyClass = getOutputStreamWrapperClass(rubyRuntime);

final IRubyObject wrapper = rubyClass.allocate();

Expand Down Expand Up @@ -53,18 +52,16 @@ public static RubyClass getOrCreateOutputStreamWrapperClass(final Ruby rubyRunti
return outputStreamWrapperClass;
}

final RubyClass rubyClass = asciidoctorModule.defineClassUnder(RUBY_CLASS_NAME, rubyRuntime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(final Ruby runtime, final RubyClass klazz) {
return new RubyOutputStreamWrapper(runtime, klazz);
}
});

final RubyClass rubyClass = asciidoctorModule.defineClassUnder(RUBY_CLASS_NAME, rubyRuntime.getObject(), RubyOutputStreamWrapper::new);
rubyClass.defineAnnotatedMethods(RubyOutputStreamWrapper.class);

return rubyClass;
}

private static RubyClass getOutputStreamWrapperClass(final Ruby rubyRuntime) {
RubyModule asciidoctorModule = rubyRuntime.getModule("AsciidoctorJ");
return asciidoctorModule.getClass(RUBY_CLASS_NAME);
}

@JRubyMethod(name = "write", required = 1)
public IRubyObject write(ThreadContext context, IRubyObject arg) throws IOException {
writeToStream(arg);
Expand Down

0 comments on commit 1ef4aed

Please sign in to comment.