/*
* Copyright 2012-2017 the original author or authors.
*
* 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.glowroot.agent.embedded.init;
import java.util.List;
import javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Class loading is also a bad idea inside of JVM shutdown hooks, see
// https://bugs.openjdk.java.net/browse/JDK-7142035
class PreInitializeStorageShutdownClasses {
private static final Logger logger =
LoggerFactory.getLogger(PreInitializeStorageShutdownClasses.class);
private PreInitializeStorageShutdownClasses() {}
static void preInitializeClasses() {
ClassLoader loader = PreInitializeStorageShutdownClasses.class.getClassLoader();
for (String type : usedTypes()) {
initialize(type, loader);
}
for (String type : maybeUsedTypes()) {
if (exists(type)) {
initialize(type, loader);
}
}
}
private static void initialize(String type, @Nullable ClassLoader loader) {
if (type.equals("org.h2.value.ValueGeometry")) {
// this type depends on an optional third party library and is not really used
// (initializing the class throws an error due to the dependency)
return;
}
try {
Class.forName(type, true, loader);
} catch (ClassNotFoundException e) {
logger.warn("class not found: {}", type);
// log exception at trace level
logger.trace(e.getMessage(), e);
}
}
@VisibleForTesting
static List<String> usedTypes() {
List<String> types = Lists.newArrayList();
types.addAll(getGlowrootUsedTypes());
types.addAll(getH2UsedTypes());
return types;
}
private static List<String> getGlowrootUsedTypes() {
List<String> types = Lists.newArrayList();
types.add("org.glowroot.agent.embedded.util.CappedDatabase");
types.add("org.glowroot.agent.embedded.util.CappedDatabase$ShutdownHookThread");
types.add("org.glowroot.agent.embedded.util.CappedDatabaseOutputStream");
types.add("org.glowroot.agent.embedded.util.DataSource");
types.add("org.glowroot.agent.embedded.util.DataSource$ShutdownHookThread");
return types;
}
private static List<String> getH2UsedTypes() {
List<String> types = Lists.newArrayList();
types.add("org.h2.api.ErrorCode");
types.add("org.h2.api.JavaObjectSerializer");
types.add("org.h2.command.CommandInterface");
types.add("org.h2.compress.CompressDeflate");
types.add("org.h2.compress.CompressLZF");
types.add("org.h2.compress.CompressNo");
types.add("org.h2.compress.Compressor");
types.add("org.h2.engine.Constants");
types.add("org.h2.engine.SessionInterface");
types.add("org.h2.engine.SysProperties");
types.add("org.h2.expression.ParameterInterface");
types.add("org.h2.jdbc.JdbcArray");
types.add("org.h2.jdbc.JdbcBatchUpdateException");
types.add("org.h2.jdbc.JdbcBlob");
types.add("org.h2.jdbc.JdbcBlob$1");
types.add("org.h2.jdbc.JdbcBlob$2");
types.add("org.h2.jdbc.JdbcCallableStatement");
types.add("org.h2.jdbc.JdbcClob");
types.add("org.h2.jdbc.JdbcClob$1");
types.add("org.h2.jdbc.JdbcClob$2");
types.add("org.h2.jdbc.JdbcConnection");
types.add("org.h2.jdbc.JdbcDatabaseMetaData");
types.add("org.h2.jdbc.JdbcParameterMetaData");
types.add("org.h2.jdbc.JdbcPreparedStatement");
types.add("org.h2.jdbc.JdbcResultSet");
types.add("org.h2.jdbc.JdbcResultSetMetaData");
types.add("org.h2.jdbc.JdbcSQLException");
types.add("org.h2.jdbc.JdbcSavepoint");
types.add("org.h2.jdbc.JdbcStatement");
types.add("org.h2.message.DbException");
types.add("org.h2.message.Trace");
types.add("org.h2.message.TraceObject");
types.add("org.h2.message.TraceSystem");
types.add("org.h2.message.TraceWriter");
types.add("org.h2.mvstore.DataUtils");
types.add("org.h2.result.ResultInterface");
types.add("org.h2.result.UpdatableRow");
types.add("org.h2.store.Data");
types.add("org.h2.store.DataHandler");
types.add("org.h2.store.FileStore");
types.add("org.h2.store.FileStoreInputStream");
types.add("org.h2.store.LobStorageInterface");
types.add("org.h2.store.fs.FilePath");
types.add("org.h2.store.fs.FileUtils");
types.add("org.h2.tools.CompressTool");
types.add("org.h2.tools.SimpleResultSet");
types.add("org.h2.tools.SimpleResultSet$Column");
types.add("org.h2.tools.SimpleResultSet$SimpleArray");
types.add("org.h2.tools.SimpleRowSource");
types.add("org.h2.util.BitField");
types.add("org.h2.util.CloseWatcher");
types.add("org.h2.util.DateTimeUtils");
types.add("org.h2.util.IOUtils");
types.add("org.h2.util.MathUtils");
types.add("org.h2.util.New");
types.add("org.h2.util.SortedProperties");
types.add("org.h2.util.StatementBuilder");
types.add("org.h2.util.StringUtils");
types.add("org.h2.util.Task");
types.add("org.h2.util.Utils");
types.add("org.h2.util.Utils$1");
types.add("org.h2.util.Utils$ClassFactory");
types.add("org.h2.value.CompareMode");
types.add("org.h2.value.DataType");
types.add("org.h2.value.Value");
types.add("org.h2.value.Value$ValueBlob");
types.add("org.h2.value.Value$ValueClob");
types.add("org.h2.value.ValueArray");
types.add("org.h2.value.ValueBoolean");
types.add("org.h2.value.ValueByte");
types.add("org.h2.value.ValueBytes");
types.add("org.h2.value.ValueDate");
types.add("org.h2.value.ValueDecimal");
types.add("org.h2.value.ValueDouble");
types.add("org.h2.value.ValueFloat");
types.add("org.h2.value.ValueGeometry");
types.add("org.h2.value.ValueInt");
types.add("org.h2.value.ValueJavaObject");
types.add("org.h2.value.ValueJavaObject$NotSerialized");
types.add("org.h2.value.ValueLobDb");
types.add("org.h2.value.ValueLong");
types.add("org.h2.value.ValueNull");
types.add("org.h2.value.ValueResultSet");
types.add("org.h2.value.ValueShort");
types.add("org.h2.value.ValueString");
types.add("org.h2.value.ValueStringFixed");
types.add("org.h2.value.ValueStringIgnoreCase");
types.add("org.h2.value.ValueTime");
types.add("org.h2.value.ValueTimestamp");
types.add("org.h2.value.ValueUuid");
return types;
}
@VisibleForTesting
static List<String> maybeUsedTypes() {
List<String> types = Lists.newArrayList();
// these are special classes generated by javac (but not by the eclipse compiler) to handle
// accessing the private constructor in an enclosed type
// (see http://stackoverflow.com/questions/2883181)
types.add("org.glowroot.common.Reflections$1");
types.add("org.glowroot.core.weaving.AnalyzedClass$1");
types.add("org.glowroot.core.weaving.Weaver$1");
types.add("org.glowroot.core.weaving.WeavingMethodVisitor$1");
// this is a special class generated by javac (but not by the eclipse compiler) to handle
// enum switch statements
// (see http://stackoverflow.com/questions/1834632/java-enum-and-additional-class-files)
types.add("org.glowroot.core.weaving.AdviceMatcher$1");
return types;
}
private static boolean exists(String type) {
try {
Class.forName(type);
return true;
} catch (ClassNotFoundException e) {
// log exception at trace level
logger.trace(e.getMessage(), e);
return false;
}
}
}