From a8ecfd058a46a00ea76624a516b6def793c53821 Mon Sep 17 00:00:00 2001 From: PJ Fanning 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.

+ */ +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 _loggers = new HashMap(); + + /** + * 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 loggerClass = + (Class) 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.

+ */ +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: + *

+     * if (logger.check(XBLogger.INFO)) {
+     *     logger.log(XBLogger.INFO, "Avoid concatenating " + " strings and evaluating " + functions());
+     * }
+     * 
+ * + * @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