Added AsciidoctorJ interface and AsciidoctorJ.Factory
MODIFY
asciidoctorj-api/src/main/java/org/asciidoctor/Asciidoctor.java
asciidoctorj-api/src/main/java/org/asciidoctor/Asciidoctor.java
@@ -12,13 +12,11 @@ import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
-import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -508,4 +506,11 @@ public interface Asciidoctor {
void unregisterLogHandler(LogHandler logHandler);
+ default <T> T unwrap(Class<T> clazz) {
+ if (clazz.isAssignableFrom(getClass())) {
+ return clazz.cast(this);
+ }
+ throw new IllegalArgumentException("Cannot unwrap to " + clazz.getName());
+ }
+
}

MODIFY
asciidoctorj-arquillian-extension/src/main/java/org/asciidoctor/arquillian/AsciidoctorResourceProvider.java
asciidoctorj-arquillian-extension/src/main/java/org/asciidoctor/arquillian/AsciidoctorResourceProvider.java
@@ -3,6 +3,7 @@ package org.asciidoctor.arquillian;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.arquillian.api.Shared;
import org.asciidoctor.arquillian.api.Unshared;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject;
@@ -18,7 +19,7 @@ public class AsciidoctorResourceProvider implements ResourceProvider {
@Override
public boolean canProvide(Class<?> type) {
- return Asciidoctor.class == type;
+ return Asciidoctor.class == type || AsciidoctorJ.class == type;
}
@Override

MODIFY
asciidoctorj-arquillian-extension/src/main/java/org/asciidoctor/arquillian/AsciidoctorTestObserver.java
asciidoctorj-arquillian-extension/src/main/java/org/asciidoctor/arquillian/AsciidoctorTestObserver.java
@@ -3,6 +3,7 @@ package org.asciidoctor.arquillian;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.arquillian.api.Shared;
import org.asciidoctor.arquillian.api.Unshared;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.util.ClasspathResources;
import org.jboss.arquillian.core.api.InstanceProducer;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
@@ -37,7 +38,10 @@ public class AsciidoctorTestObserver {
}
public void beforeTestClassCreateSharedAsciidoctorInstance(@Observes(precedence = -100) BeforeClass beforeClass) {
- if (isSharedInstanceRequired(beforeClass.getTestClass().getJavaClass(), Asciidoctor.class)) {
+ if (isSharedInstanceRequired(beforeClass.getTestClass().getJavaClass(), AsciidoctorJ.class)) {
+ scopedAsciidoctor.get().setSharedAsciidoctor(
+ AsciidoctorJ.Factory.create());
+ } else if (isSharedInstanceRequired(beforeClass.getTestClass().getJavaClass(), Asciidoctor.class)) {
scopedAsciidoctor.get().setSharedAsciidoctor(
Asciidoctor.Factory.create());
}
@@ -59,7 +63,11 @@ public class AsciidoctorTestObserver {
public void beforeTestCreateUnsharedAsciidoctorInstance(@Observes(precedence = 5) Before before) {
- if (isUnsharedInstanceRequired(before.getTestClass().getJavaClass(), Asciidoctor.class)
+ if (isUnsharedInstanceRequired(before.getTestClass().getJavaClass(), AsciidoctorJ.class)
+ || isUnsharedInstanceRequired(before.getTestMethod(), Asciidoctor.class)) {
+ scopedAsciidoctor.get().setUnsharedAsciidoctor(
+ AsciidoctorJ.Factory.create());
+ } else if (isUnsharedInstanceRequired(before.getTestClass().getJavaClass(), Asciidoctor.class)
|| isUnsharedInstanceRequired(before.getTestMethod(), Asciidoctor.class)) {
scopedAsciidoctor.get().setUnsharedAsciidoctor(
Asciidoctor.Factory.create());

ADD
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/AsciidoctorJ.java
+package org.asciidoctor.ruby;
+
+import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.ruby.internal.JRubyAsciidoctor;
+
+import java.util.List;
+
+public interface AsciidoctorJ extends Asciidoctor {
+
+
+ /**
+ * Creates an Ruby extension registry ready to be used for registering all processors
+ *
+ * @return Extension Registry object.
+ */
+ RubyExtensionRegistry rubyExtensionRegistry();
+
+ /**
+ * Factory for creating a new instance of Asciidoctor interface.
+ *
+ * @author lordofthejars
+ */
+ public static final class Factory {
+
+ private Factory() {
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor.
+ *
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ * Ruby calls.
+ */
+ public static AsciidoctorJ create() {
+ return JRubyAsciidoctor.create();
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor and sets GEM_PATH environment
+ * variable to provided gemPath. This method is mostly used in OSGi
+ * environments.
+ *
+ * @param gemPath where gems are located.
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ * Ruby calls.
+ */
+ public static AsciidoctorJ create(String gemPath) {
+ return JRubyAsciidoctor.create(gemPath);
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor and sets loadPath to provided paths. This method is mostly used in OSGi
+ * environments.
+ *
+ * @param loadPaths where Ruby libraries are located.
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ * Ruby calls.
+ */
+ public static AsciidoctorJ create(List<String> loadPaths) {
+ return JRubyAsciidoctor.create(loadPaths);
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor and sets a specific classloader for the JRuby runtime to use.
+ * This method is for use in environments like OSGi.
+ * To initialize Asciidoctor in OSGi create the Asciidoctor instance like this:
+ *
+ * <pre>
+ * org.jruby.javasupport.JavaEmbedUtils.initialize(Arrays.asList("uri:classloader:/gems/asciidoctor-1.5.8/lib"));
+ * Asciidoctor asciidoctor = Asciidoctor.Factory.create(this.getClass().getClassLoader()); <3>
+ * </pre>
+ *
+ * @param classloader
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ * Ruby calls.
+ */
+ public static AsciidoctorJ create(ClassLoader classloader) {
+ return JRubyAsciidoctor.create(classloader);
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor and sets a specific classloader and gempath for the JRuby runtime to use.
+ * This method is for use in environments like OSGi.
+ * To initialize Asciidoctor in OSGi create the Asciidoctor instance like this:
+ *
+ * <pre>
+ * org.jruby.javasupport.JavaEmbedUtils.initialize(Arrays.asList("uri:classloader:/gems/asciidoctor-1.5.8/lib"));
+ * Asciidoctor asciidoctor = Asciidoctor.Factory.create(this.getClass().getClassLoader()); <3>
+ * </pre>
+ *
+ * @param classloader
+ * @param gemPath
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ */
+ public static AsciidoctorJ create(ClassLoader classloader, String gemPath) {
+ return JRubyAsciidoctor.create(classloader, gemPath);
+ }
+
+ /**
+ * Creates a new instance of Asciidoctor and sets loadPath to provided paths.
+ * The gem path of the Ruby instance is set to the gemPath parameter.
+ *
+ * @param loadPaths where Ruby libraries are located.
+ * @param gemPath where gems are located.
+ * @return Asciidoctor instance which uses JRuby to wraps Asciidoctor
+ * Ruby calls.
+ */
+ public static AsciidoctorJ create(List<String> loadPaths, String gemPath) {
+ return JRubyAsciidoctor.create(loadPaths, gemPath);
+ }
+
+ }
+
+
+}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/converter/internal/ConverterRegistryExecutor.java
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/converter/internal/ConverterRegistryExecutor.java
package org.asciidoctor.ruby.converter.internal;
import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.ruby.converter.spi.ConverterRegistry;
import java.util.ServiceLoader;
public class ConverterRegistryExecutor {
- private Asciidoctor asciidoctor;
+ private AsciidoctorJ asciidoctor;
- public ConverterRegistryExecutor(Asciidoctor asciidoctor) {
+ public ConverterRegistryExecutor(AsciidoctorJ asciidoctor) {
this.asciidoctor = asciidoctor;
}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/extension/internal/ExtensionRegistryExecutor.java
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/extension/internal/ExtensionRegistryExecutor.java
package org.asciidoctor.ruby.extension.internal;
-import java.util.ServiceLoader;
-
-import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.ruby.extension.spi.ExtensionRegistry;
+import java.util.ServiceLoader;
+
public class ExtensionRegistryExecutor {
- private Asciidoctor asciidoctor;
+ private AsciidoctorJ asciidoctor;
- public ExtensionRegistryExecutor(Asciidoctor asciidoctor) {
+ public ExtensionRegistryExecutor(AsciidoctorJ asciidoctor) {
this.asciidoctor = asciidoctor;
}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/internal/JRubyAsciidoctor.java
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/internal/JRubyAsciidoctor.java
package org.asciidoctor.ruby.internal;
-import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Attributes;
import org.asciidoctor.Options;
import org.asciidoctor.OptionsBuilder;
@@ -12,6 +11,7 @@ import org.asciidoctor.extension.ExtensionGroup;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.log.LogHandler;
import org.asciidoctor.log.LogRecord;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.ruby.DirectoryWalker;
import org.asciidoctor.ruby.RubyExtensionRegistry;
import org.asciidoctor.ruby.ast.impl.DocumentHeaderImpl;
@@ -30,7 +30,7 @@ import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
-public class JRubyAsciidoctor implements Asciidoctor, LogHandler {
+public class JRubyAsciidoctor implements AsciidoctorJ, LogHandler {
private static final Logger logger = Logger.getLogger(JRubyAsciidoctor.class.getName());
@@ -93,15 +93,15 @@ public class JRubyAsciidoctor implements Asciidoctor, LogHandler {
return asciidoctor;
}
- private static void registerConverters(Asciidoctor asciidoctor) {
+ private static void registerConverters(AsciidoctorJ asciidoctor) {
new ConverterRegistryExecutor(asciidoctor).registerAllConverters();
}
- private static void registerExtensions(Asciidoctor asciidoctor) {
+ private static void registerExtensions(AsciidoctorJ asciidoctor) {
new ExtensionRegistryExecutor(asciidoctor).registerAllExtensions();
}
- private static void registerLogHandlers(Asciidoctor asciidoctor) {
+ private static void registerLogHandlers(AsciidoctorJ asciidoctor) {
new LogHandlerRegistryExecutor(asciidoctor).registerAllLogHandlers();
}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/log/internal/LogHandlerRegistryExecutor.java
asciidoctorj-core/src/main/java/org/asciidoctor/ruby/log/internal/LogHandlerRegistryExecutor.java
package org.asciidoctor.ruby.log.internal;
-import org.asciidoctor.Asciidoctor;
import org.asciidoctor.log.LogHandler;
+import org.asciidoctor.ruby.AsciidoctorJ;
import java.util.ServiceLoader;
@@ -9,9 +9,9 @@ public class LogHandlerRegistryExecutor {
private static ServiceLoader<LogHandler> logHandlerServiceLoader = ServiceLoader
.load(LogHandler.class);
- private Asciidoctor asciidoctor;
+ private AsciidoctorJ asciidoctor;
- public LogHandlerRegistryExecutor(Asciidoctor asciidoctor) {
+ public LogHandlerRegistryExecutor(AsciidoctorJ asciidoctor) {
this.asciidoctor = asciidoctor;
}

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/WhenAnAsciidoctorClassIsInstantiatedInAnEnvironmentWithGemPath.java
asciidoctorj-core/src/test/java/org/asciidoctor/WhenAnAsciidoctorClassIsInstantiatedInAnEnvironmentWithGemPath.java
package org.asciidoctor;
import org.asciidoctor.categories.Polluted;
-import org.asciidoctor.ruby.internal.JRubyAsciidoctor;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.ruby.internal.JRubyRuntimeContext;
import org.jruby.Ruby;
import org.jruby.RubyString;
@@ -27,7 +27,7 @@ public class WhenAnAsciidoctorClassIsInstantiatedInAnEnvironmentWithGemPath {
assertThat(System.getenv("GEM_HOME"), notNullValue());
// When: A new Asciidoctor instance is created passing in a null GEM_PATH
- Asciidoctor asciidoctor = JRubyAsciidoctor.create((String) null);
+ Asciidoctor asciidoctor = AsciidoctorJ.Factory.create((String) null);
// Then: The org.jruby.JRuby instance does not see this variable
Ruby rubyRuntime = JRubyRuntimeContext.get(asciidoctor);
@@ -42,7 +42,7 @@ public class WhenAnAsciidoctorClassIsInstantiatedInAnEnvironmentWithGemPath {
assertThat(System.getenv("GEM_HOME"), notNullValue());
// When: A new Asciidoctor instance is created passing in no GEM_PATH
- Asciidoctor asciidoctor = JRubyAsciidoctor.create();
+ Asciidoctor asciidoctor = AsciidoctorJ.Factory.create();
// Then: The org.jruby.JRuby instance sees this variable
Ruby rubyRuntime = JRubyRuntimeContext.get(asciidoctor);
@@ -58,7 +58,7 @@ public class WhenAnAsciidoctorClassIsInstantiatedInAnEnvironmentWithGemPath {
assertThat(System.getenv("GEM_HOME"), notNullValue());
// When: A new Asciidoctor instance is created passing in a null GEM_PATH
- Asciidoctor asciidoctor = JRubyAsciidoctor.create(gemPath);
+ Asciidoctor asciidoctor = AsciidoctorJ.Factory.create(gemPath);
// Then: The org.jruby.JRuby instance does not see this variable
Ruby rubyRuntime = JRubyRuntimeContext.get(asciidoctor);

ADD
asciidoctorj-core/src/test/java/org/asciidoctor/WhenAnAsciidoctorJInstanceIsRequired.java
+package org.asciidoctor;
+
+import org.asciidoctor.ruby.AsciidoctorJ;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+public class WhenAnAsciidoctorJInstanceIsRequired {
+
+ private static final String DOC = "[yell]\nHello World";
+
+ @Test
+ public void shouldUnwrapAsciidoctorInstanceAndRegisterRubyExtension() throws Exception {
+ AsciidoctorJ asciidoctorj = Asciidoctor.Factory.create().unwrap(AsciidoctorJ.class);
+ asciidoctorj.rubyExtensionRegistry().loadClass(getClass().getResourceAsStream("/ruby-extensions/YellRubyBlock.rb")).block("yell", "YellRubyBlock");
+
+ String html = asciidoctorj.convert(DOC, OptionsBuilder.options().headerFooter(false));
+
+ assertThat(html, containsString("HELLO WORLD"));
+ }
+
+}

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenRubyExtensionIsRegistered.java
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenRubyExtensionIsRegistered.java
package org.asciidoctor.extension;
-import org.asciidoctor.Asciidoctor;
import org.asciidoctor.SafeMode;
import org.asciidoctor.arquillian.api.Unshared;
+import org.asciidoctor.ruby.AsciidoctorJ;
import org.asciidoctor.ruby.RubyExtensionRegistry;
-import org.asciidoctor.ruby.internal.JRubyAsciidoctor;
import org.asciidoctor.util.ClasspathResources;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
@@ -32,12 +31,12 @@ public class WhenRubyExtensionIsRegistered {
private ClasspathResources classpath;
@ArquillianResource(Unshared.class)
- private Asciidoctor asciidoctor;
+ private AsciidoctorJ asciidoctor;
@Test
public void ruby_block_processor_should_be_registered_with_explicit_block_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/YellRubyBlock.rb")).block("rubyyell", "YellRubyBlock");
String content = asciidoctor.convert(
@@ -59,7 +58,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_block_processor_should_be_registered_with_implicit_block_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/YellRubyBlock.rb")).block("YellRubyBlock");
String content = asciidoctor.convert(
@@ -81,7 +80,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_block_macro_processor_should_be_registered_with_block_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/gist-block-macro.rb")).blockMacro("mygist", "GistBlockMacro");
String content = asciidoctor.convert(
@@ -99,7 +98,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_block_macro_processor_should_be_registered_with_implicit_block_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/gist-block-macro.rb")).blockMacro("GistBlockMacro");
String content = asciidoctor.convert(
@@ -117,7 +116,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_inline_macro_processor_should_be_registered_with_macro_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/man-inline-macro.rb")).inlineMacro("myman", "ManInlineMacro");
String content = asciidoctor.convert(
@@ -136,7 +135,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_inline_macro_processor_should_be_registered_with_implicit_macro_name() {
- RubyExtensionRegistry rubyExtensionRegistry = ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry();
+ RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry();
rubyExtensionRegistry.loadClass(getClass().getResourceAsStream("/ruby-extensions/man-inline-macro.rb"))
.inlineMacro("ManInlineMacro");
@@ -157,7 +156,7 @@ public class WhenRubyExtensionIsRegistered {
public void ruby_treeprocessor_should_be_registered() {
final String rubyExtPath = classpath.getResource("ruby-extensions").getAbsolutePath();
- final JRubyAsciidoctor asciidoctor = JRubyAsciidoctor.create(singletonList(rubyExtPath));
+ final AsciidoctorJ asciidoctor = AsciidoctorJ.Factory.create(singletonList(rubyExtPath));
asciidoctor.rubyExtensionRegistry()
.requireLibrary("shell-session-tree-processor.rb")
.treeprocessor("ShellSessionTreeProcessor");
@@ -178,7 +177,7 @@ public class WhenRubyExtensionIsRegistered {
@Test
public void ruby_includeprocessor_should_be_registered() {
- ((JRubyAsciidoctor) asciidoctor).rubyExtensionRegistry()
+ asciidoctor.rubyExtensionRegistry()
.loadClass(getClass().getResourceAsStream("/ruby-extensions/response-include-processor.rb"))
.includeProcessor("ResponseIncludeProcessor");
@@ -199,7 +198,7 @@ public class WhenRubyExtensionIsRegistered {
public void ruby_postprocessor_should_be_registered() {
final String rubyExtPath = classpath.getResource("ruby-extensions").getAbsolutePath();
- final JRubyAsciidoctor asciidoctor = JRubyAsciidoctor.create(singletonList(rubyExtPath));
+ final AsciidoctorJ asciidoctor = AsciidoctorJ.Factory.create(singletonList(rubyExtPath));
asciidoctor.rubyExtensionRegistry()
.requireLibrary("xml-entity-postprocessor.rb")
.postprocessor("XmlEntityPostprocessor");
@@ -215,7 +214,7 @@ public class WhenRubyExtensionIsRegistered {
public void ruby_preprocessor_should_be_registered() {
final String rubyExtPath = classpath.getResource("ruby-extensions").getAbsolutePath();
- final JRubyAsciidoctor asciidoctor = JRubyAsciidoctor.create(singletonList(rubyExtPath));
+ final AsciidoctorJ asciidoctor = AsciidoctorJ.Factory.create(singletonList(rubyExtPath));
asciidoctor.rubyExtensionRegistry()
.requireLibrary("front-matter-preprocessor.rb")
.preprocessor("FrontMatterPreprocessor");
@@ -250,7 +249,7 @@ public class WhenRubyExtensionIsRegistered {
public void ruby_docinfoprocessor_should_be_registered() {
final String rubyExtPath = classpath.getResource("ruby-extensions").getAbsolutePath();
- final JRubyAsciidoctor asciidoctor = JRubyAsciidoctor.create(singletonList(rubyExtPath));
+ final AsciidoctorJ asciidoctor = AsciidoctorJ.Factory.create(singletonList(rubyExtPath));
asciidoctor.rubyExtensionRegistry()
.requireLibrary("view-result-docinfoprocessor.rb")
.docinfoProcessor("ViewResultDocinfoProcessor");

Added AsciidoctorJ interface and AsciidoctorJ.Factory