From a8ecfd058a46a00ea76624a516b6def793c53821 Mon Sep 17 00:00:00 2001
From: PJ Fanning <fanningpj@apache.org>
Date: Sat, 26 May 2018 08:31:14 +0000
Subject: [PATCH] fix build and bring in fixes from
 https://github.com/pjfanning/xmlbeans/blob/trunk/CHANGES.txt

[Part of 3.0.0 backport of
https://github.com/apache/xmlbeans/commit/a8ecfd0]

---
 .../xmlbeans/impl/store/NullLogger.java       |  81 ++++++++++++
 .../apache/xmlbeans/impl/store/SAXHelper.java |  99 +++++++++++++++
 .../xmlbeans/impl/store/XBLogFactory.java     | 119 ++++++++++++++++++
 .../apache/xmlbeans/impl/store/XBLogger.java  | 115 +++++++++++++++++
 4 files changed, 414 insertions(+)
 create mode 100644 src/store/org/apache/xmlbeans/impl/store/NullLogger.java
 create mode 100644 src/store/org/apache/xmlbeans/impl/store/SAXHelper.java
 create mode 100644 src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java
 create mode 100644 src/store/org/apache/xmlbeans/impl/store/XBLogger.java

diff --git a/src/store/org/apache/xmlbeans/impl/store/NullLogger.java b/src/store/org/apache/xmlbeans/impl/store/NullLogger.java
new file mode 100644
index 00000000..aca8d1d5
--- /dev/null
+++ b/src/store/org/apache/xmlbeans/impl/store/NullLogger.java
@@ -0,0 +1,81 @@
+/*   Copyright 2017 The Apache Software Foundation
+ *
+ *   Licensed 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.xmlbeans.impl.store;
+
+/**
+ * A logger class that strives to make it as easy as possible for
+ * developers to write log calls, while simultaneously making those
+ * calls as cheap as possible by performing lazy evaluation of the log
+ * message.<p>
+ */
+public class NullLogger extends XBLogger {
+    @Override
+    public void initialize(final String cat) {
+       // do nothing
+    }
+
+    /**
+     * Log a message
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param obj1 The object to log.
+     */
+
+    @Override
+    protected void _log(final int level, final Object obj1) {
+        // do nothing
+    }
+
+    /**
+     * Log a message
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param obj1 The object to log.  This is converted to a string.
+     * @param exception An exception to be logged
+     */
+    @Override
+    protected void _log(int level, Object obj1, final Throwable exception) {
+        // do nothing
+    }
+
+    /**
+     * Log a message. Lazily appends Object parameters together.
+     * If the last parameter is a {@link Throwable} it is logged specially.
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param objs the objects to place in the message
+     */
+    @Override
+    public void log(int level, Object... objs) {
+        // do nothing
+    }
+
+    
+    /**
+     * Check if a logger is enabled to log at the specified level
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     */
+    @Override
+    public boolean check(final int level) {
+       return false;
+    }
+}
+
+
+
+
+
diff --git a/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java b/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java
new file mode 100644
index 00000000..67fb3a0e
--- /dev/null
+++ b/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java
@@ -0,0 +1,99 @@
+/*   Copyright 2017 The Apache Software Foundation
+ *
+ *   Licensed 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.xmlbeans.impl.store;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Provides handy methods for working with SAX parsers and readers
+ */
+public final class SAXHelper {
+    private static final XBLogger logger = XBLogFactory.getLogger(SAXHelper.class);
+    private static long lastLog;
+
+    private SAXHelper() {}
+
+    /**
+     * Creates a new SAX XMLReader, with sensible defaults
+     */
+    public static synchronized XMLReader newXMLReader() throws SAXException, ParserConfigurationException {
+        XMLReader xmlReader = saxFactory.newSAXParser().getXMLReader();
+        xmlReader.setEntityResolver(IGNORING_ENTITY_RESOLVER);
+        trySetSAXFeature(xmlReader, XMLConstants.FEATURE_SECURE_PROCESSING);
+        trySetXercesSecurityManager(xmlReader);
+        return xmlReader;
+    }
+    
+    static final EntityResolver IGNORING_ENTITY_RESOLVER = new EntityResolver() {
+        @Override
+        public InputSource resolveEntity(String publicId, String systemId)
+                throws SAXException, IOException {
+            return new InputSource(new StringReader(""));
+        }
+    };
+    
+    private static final SAXParserFactory saxFactory;
+    static {
+        saxFactory = SAXParserFactory.newInstance();
+        saxFactory.setValidating(false);
+        saxFactory.setNamespaceAware(true);
+    }
+            
+    private static void trySetSAXFeature(XMLReader xmlReader, String feature) {
+        try {
+            xmlReader.setFeature(feature, true);
+        } catch (Exception e) {
+            logger.log(XBLogger.WARN, "SAX Feature unsupported", feature, e);
+        } catch (AbstractMethodError ame) {
+            logger.log(XBLogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame);
+        }
+    }
+    
+    private static void trySetXercesSecurityManager(XMLReader xmlReader) {
+        // Try built-in JVM one first, standalone if not
+        for (String securityManagerClassName : new String[] {
+                "com.sun.org.apache.xerces.internal.util.SecurityManager",
+                "org.apache.xerces.util.SecurityManager"
+        }) {
+            try {
+                Object mgr = Class.forName(securityManagerClassName).newInstance();
+                Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
+                setLimit.invoke(mgr, 4096);
+                xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr);
+                // Stop once one can be setup without error
+                return;
+            } catch (Throwable e) {     // NOSONAR - also catch things like NoClassDefError here
+                // throttle the log somewhat as it can spam the log otherwise
+                if(System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5)) {
+                    logger.log(XBLogger.WARN, "SAX Security Manager could not be setup [log suppressed for 5 minutes]", e);
+                    lastLog = System.currentTimeMillis();
+                }
+            }
+        }
+    }
+}
diff --git a/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java b/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java
new file mode 100644
index 00000000..f31d4db7
--- /dev/null
+++ b/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java
@@ -0,0 +1,119 @@
+/*   Copyright 2017 The Apache Software Foundation
+ *
+ *   Licensed 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.xmlbeans.impl.store;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides logging without clients having to mess with
+ * configuration/initialization.
+ *
+ * @author Andrew C. Oliver (acoliver at apache dot org)
+ * @author Marc Johnson (mjohnson at apache dot org)
+ * @author Nicola Ken Barozzi (nicolaken at apache.org)
+ */
+public final class XBLogFactory {
+    /**
+     * Map of XBLogger instances, with classes as keys
+     */
+    private static final Map<String,XBLogger> _loggers = new HashMap<String,XBLogger>();
+
+    /**
+     * A common instance of NullLogger, as it does nothing
+     *  we only need the one
+     */
+    private static final XBLogger _nullLogger = new NullLogger();
+    /**
+     * The name of the class to use. Initialised the
+     *  first time we need it
+     */
+    static String _loggerClassName = null;
+
+    /**
+     * Construct a XBLogFactory.
+     */
+    private XBLogFactory() {}
+
+    /**
+     * Get a logger, based on a class name
+     *
+     * @param theclass the class whose name defines the log
+     *
+     * @return a XBLogger for the specified class
+     */
+    public static XBLogger getLogger(final Class<?> theclass) {
+        return getLogger(theclass.getName());
+    }
+
+    /**
+     * Get a logger, based on a String
+     *
+     * @param cat the String that defines the log
+     *
+     * @return a XBLogger for the specified class
+     */
+    public static XBLogger getLogger(final String cat) {
+        // If we haven't found out what logger to use yet,
+        //  then do so now
+        // Don't look it up until we're first asked, so
+        //  that our users can set the system property
+        //  between class loading and first use
+        if(_loggerClassName == null) {
+        	try {
+        		_loggerClassName = System.getProperty("org.apache.xmlbeans.impl.store.XBLogger");
+        	} catch(Exception e) {
+                // ignore any exception here
+            }
+
+        	// Use the default logger if none specified,
+        	//  or none could be fetched
+        	if(_loggerClassName == null) {
+                _loggerClassName = _nullLogger.getClass().getName();
+        	}
+        }
+
+        // Short circuit for the null logger, which
+        //  ignores all categories
+        if(_loggerClassName.equals(_nullLogger.getClass().getName())) {
+        	return _nullLogger;
+        }
+
+
+        // Fetch the right logger for them, creating
+        //  it if that's required
+        XBLogger logger = _loggers.get(cat);
+        if (logger == null) {
+            try {
+                @SuppressWarnings("unchecked")
+                Class<? extends XBLogger> loggerClass =
+                    (Class<? extends XBLogger>) Class.forName(_loggerClassName);
+                logger = loggerClass.newInstance();
+                logger.initialize(cat);
+            } catch(Exception e) {
+                // Give up and use the null logger
+                logger = _nullLogger;
+                _loggerClassName = _nullLogger.getClass().getName();
+            }
+
+            // Save for next time
+            _loggers.put(cat, logger);
+        }
+        return logger;
+    }
+}
+
+
diff --git a/src/store/org/apache/xmlbeans/impl/store/XBLogger.java b/src/store/org/apache/xmlbeans/impl/store/XBLogger.java
new file mode 100644
index 00000000..fa605112
--- /dev/null
+++ b/src/store/org/apache/xmlbeans/impl/store/XBLogger.java
@@ -0,0 +1,115 @@
+/*   Copyright 2017 The Apache Software Foundation
+ *
+ *   Licensed 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.xmlbeans.impl.store;
+
+/**
+ * A logger interface that strives to make it as easy as possible for
+ * developers to write log calls, while simultaneously making those
+ * calls as cheap as possible by performing lazy evaluation of the log
+ * message.<p>
+ */
+public abstract class XBLogger {
+
+    public static final int DEBUG = 1;
+    public static final int INFO  = 3;
+    public static final int WARN  = 5;
+    public static final int ERROR = 7;
+    public static final int FATAL = 9;
+
+    /** Short strings for numeric log level. Use level as array index. */
+    protected static final String LEVEL_STRINGS_SHORT[] = {"?", "D", "?", "I", "?", "W", "?", "E", "?", "F", "?"};
+    /** Long strings for numeric log level. Use level as array index. */
+    protected static final String LEVEL_STRINGS[] = {"?0?", "DEBUG", "?2?", "INFO", "?4?", "WARN", "?6?", "ERROR", "?8?", "FATAL", "?10+?"};
+
+
+    /**
+     * package scope so it cannot be instantiated outside of the util
+     * package. You need a XBLogger? Go to the XBLogFactory for one
+     */
+    XBLogger() {
+        // no fields to initialize
+    }
+
+    abstract public void initialize(String cat);
+
+    /**
+     * Log a message
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param obj1 The object to log.  This is converted to a string.
+     */
+    abstract protected void _log(int level, Object obj1);
+
+    /**
+     * Log a message
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param obj1 The object to log.  This is converted to a string.
+     * @param exception An exception to be logged
+     */
+    abstract protected void _log(int level, Object obj1, final Throwable exception);
+
+
+    /**
+     * Check if a logger is enabled to log at the specified level
+     * This allows code to avoid building strings or evaluating functions in
+     * the arguments to log.
+     * 
+     * An example:
+     * <code><pre>
+     * if (logger.check(XBLogger.INFO)) {
+     *     logger.log(XBLogger.INFO, "Avoid concatenating " + " strings and evaluating " + functions());
+     * }
+     * </pre></code>
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     */
+    abstract public boolean check(int level);
+
+   /**
+     * Log a message. Lazily appends Object parameters together.
+     * If the last parameter is a {@link Throwable} it is logged specially.
+     *
+     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+     * @param objs the objects to place in the message
+     */
+    public void log(int level, Object... objs) {
+        if (!check(level)) return;
+        StringBuilder sb = new StringBuilder(32);
+        Throwable lastEx = null;
+        for (int i=0; i<objs.length; i++) {
+            if (i == objs.length-1 && objs[i] instanceof Throwable) {
+                lastEx = (Throwable)objs[i];
+            } else {
+                sb.append(objs[i]);
+            }
+        }
+        
+        String msg = sb.toString();
+        msg = msg.replaceAll("[\r\n]+", " ");  // log forging escape
+        
+        // somehow this ambiguity works and doesn't lead to a loop,
+        // but it's confusing ...
+        if (lastEx == null) {
+            _log(level, msg);
+        } else {
+            _log(level, msg, lastEx);
+        }
+    }
+}
+
+
+
-- 
2.23.0

