[OPENJPA-2838] jul log factory
diff --git a/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java b/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
index c8be809..c79535f 100644
--- a/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
+++ b/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
@@ -22,6 +22,7 @@
 import org.apache.openjpa.enhance.AsmAdaptor;
 import org.apache.openjpa.enhance.PCEnhancer;
 import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.lib.log.JULLogFactory;
 import org.apache.openjpa.lib.log.LogFactory;
 import org.apache.openjpa.lib.log.LogFactoryImpl;
 import org.apache.openjpa.lib.log.SLF4JLogFactory;
@@ -125,7 +126,11 @@
                 try {
                     return new SLF4JLogFactory();
                 } catch (final Error | Exception e) {
-                    return new LogFactoryImpl();
+                    try {
+                        return new LogFactoryImpl();
+                    } catch (final Error | Exception e2) {
+                        return new JULLogFactory();
+                    }
                 }
             }
             return logFactory.asSubclass(LogFactory.class).getConstructor().newInstance();
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
index 14076c4..d7d54c3 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
@@ -158,6 +158,7 @@
             "commons", "org.apache.openjpa.lib.log.CommonsLogFactory",
             "log4j", "org.apache.openjpa.lib.log.Log4JLogFactory",
             "slf4j", "org.apache.openjpa.lib.log.SLF4JLogFactory",
+            "jul", "org.apache.openjpa.lib.log.JULLogFactory",
             "none", NoneLogFactory.class.getName(),
             "false", NoneLogFactory.class.getName(),
         };
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/log/JULLogFactory.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/log/JULLogFactory.java
new file mode 100644
index 0000000..72a2727
--- /dev/null
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/log/JULLogFactory.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.lib.log;
+
+import org.apache.openjpa.lib.conf.Configurable;
+import org.apache.openjpa.lib.conf.Configuration;
+import org.apache.openjpa.lib.conf.Value;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JULLogFactory implements LogFactory, Configurable {
+    private ClassLoader classLoader;
+
+    public JULLogFactory() {
+        classLoader = Thread.currentThread().getContextClassLoader();
+    }
+
+    @Override
+    public Log getLog(final String channel) {
+        final Thread thread;
+        final ClassLoader oldLoader;
+        if (classLoader != null) {
+            thread = Thread.currentThread();
+            oldLoader = thread.getContextClassLoader();
+        } else {
+            thread = null;
+            oldLoader = null;
+        }
+        try {
+            return new JULLog(Logger.getLogger(channel));
+        } finally {
+            if (thread != null) {
+                thread.setContextClassLoader(oldLoader);
+            }
+        }
+    }
+
+    @Override
+    public void setConfiguration(final Configuration conf) {
+        final Value value = conf.getValue("Log.JULFactory");
+        if (value != null) {
+            final String string = value.getString();
+            if (string != null && string.contains("SkipStartClassLoader=true")) {
+                classLoader = null;
+            }
+        }
+    }
+
+    @Override
+    public void startConfiguration() {
+        // no-op
+    }
+
+    @Override
+    public void endConfiguration() {
+        // no-op
+    }
+
+    private static class JULLog implements Log {
+        private final Logger logger;
+
+        public JULLog(final Logger logger) {
+            this.logger = logger;
+        }
+
+        @Override
+        public boolean isTraceEnabled() {
+            return logger.isLoggable(Level.FINEST);
+        }
+
+        @Override
+        public boolean isInfoEnabled() {
+            return logger.isLoggable(Level.INFO);
+        }
+
+        @Override
+        public boolean isWarnEnabled() {
+            return logger.isLoggable(Level.WARNING);
+        }
+
+        @Override
+        public boolean isErrorEnabled() {
+            return logger.isLoggable(Level.SEVERE);
+        }
+
+        @Override
+        public boolean isFatalEnabled() {
+            return logger.isLoggable(Level.SEVERE);
+        }
+
+        @Override
+        public void trace(final Object o) {
+            logger.finest(String.valueOf(o));
+        }
+
+        @Override
+        public void trace(final Object o, final Throwable t) {
+            logger.log(Level.FINEST, String.valueOf(o), t);
+        }
+
+        @Override
+        public void info(final Object o) {
+            logger.info(String.valueOf(o));
+        }
+
+        @Override
+        public void info(final Object o, final Throwable t) {
+            logger.log(Level.INFO, String.valueOf(o), t);
+        }
+
+        @Override
+        public void warn(final Object o) {
+            logger.warning(String.valueOf(o));
+        }
+
+        @Override
+        public void warn(final Object o, final Throwable t) {
+            logger.log(Level.WARNING, String.valueOf(o), t);
+        }
+
+        @Override
+        public void error(final Object o) {
+            logger.severe(String.valueOf(o));
+        }
+
+        @Override
+        public void error(final Object o, final Throwable t) {
+            logger.log(Level.SEVERE, String.valueOf(o), t);
+        }
+
+        @Override
+        public void fatal(final Object o) {
+            error(o);
+        }
+
+        @Override
+        public void fatal(final Object o, final Throwable t) {
+            error(o, t);
+        }
+    }
+}
diff --git a/openjpa-lib/src/test/java/org/apache/openjpa/lib/log/JULLogFactoryTest.java b/openjpa-lib/src/test/java/org/apache/openjpa/lib/log/JULLogFactoryTest.java
new file mode 100644
index 0000000..ce54f11
--- /dev/null
+++ b/openjpa-lib/src/test/java/org/apache/openjpa/lib/log/JULLogFactoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.lib.log;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import static org.junit.Assert.assertEquals;
+
+public class JULLogFactoryTest {
+    @Test
+    public void log() {
+        final JULLogFactory factory = new JULLogFactory();
+        final String logger = getClass().getName() + "__log";
+        final Logger jul = Logger.getLogger(logger);
+        final Collection<LogRecord> records = new ArrayList<>();
+        final Handler handler = new Handler() {
+            @Override
+            public void publish(final LogRecord record) {
+                records.add(record);
+            }
+
+            @Override
+            public void flush() {
+                // no-op
+            }
+
+            @Override
+            public void close() throws SecurityException {
+                flush();
+            }
+        };
+        jul.addHandler(handler);
+        final Log log = factory.getLog(logger);
+        log.info(">test<");
+        jul.removeHandler(handler);
+        assertEquals(1, records.size());
+        assertEquals(">test<", records.iterator().next().getMessage());
+    }
+}