All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.agent.init.PreCheckLoadedClasses Maven / Gradle / Ivy

There is a newer version: 0.14.0-beta.3
Show newest version
/*
 * Copyright 2018-2019 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.init;

import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.Nullable;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.Logger;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.LoggerFactory;

import org.glowroot.agent.weaving.ImportantClassNames;

// LIMIT DEPENDENCY USAGE IN THIS CLASS SO IT DOESN'T TRIGGER ANY CLASS LOADING ON ITS OWN
public class PreCheckLoadedClasses {

    // org.glowroot.agent.jul is shaded to org.glowroot.agent.jul
    private static final String SHADE_PROOF_JUL_LOGGER_CLASS_NAME =
            "_java.util.logging.Logger".substring(1);

    private static final Set IMPORTANT_CLASS_NAMES;

    // only check for org.glowroot.agent.jul.Logger under test, since just want to make sure glowroot
    // doesn't accidentally initialize org.glowroot.agent.jul.Logger itself, but it's not a problem
    // for glowroot if someone else initializes it early (e.g. and weblogic does)
    private static final boolean CHECK_FOR_JUL_LOGGER =
            System.getProperty("glowroot.test.dir") != null && isShaded();

    static {
        List importantClassNames =
                Arrays.asList(ImportantClassNames.JBOSS_URL_HACK_CLASS_NAME.replace('/', '.'));
        IMPORTANT_CLASS_NAMES = new HashSet(importantClassNames);
    }

    private PreCheckLoadedClasses() {}

    static boolean isImportantClass(String className, Class clazz) {
        return IMPORTANT_CLASS_NAMES.contains(className)
                || isImportantRunnableOrCallable(className, clazz)
                || className.equals("java.net.HttpURLConnection")
                || CHECK_FOR_JUL_LOGGER && className.equals(SHADE_PROOF_JUL_LOGGER_CLASS_NAME);
    }

    private static boolean isImportantRunnableOrCallable(String className, Class clazz) {
        return className.startsWith("java.util.concurrent.") && !clazz.isInterface()
                && (Runnable.class.isAssignableFrom(clazz)
                        || Callable.class.isAssignableFrom(clazz));
    }

    private static boolean isShaded() {
        try {
            Class.forName("org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.Logger");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    public static class PreCheckClassFileTransformer implements ClassFileTransformer {

        private static volatile @MonotonicNonNull Logger logger;

        private final Set importantInternalNames;
        private final String shadeProofJulLoggerInternalName =
                SHADE_PROOF_JUL_LOGGER_CLASS_NAME.replace('.', '/');

        private final Map importantClassLoadingPoints =
                new ConcurrentHashMap();

        public PreCheckClassFileTransformer() {
            List internalNames = new ArrayList();
            for (String className : IMPORTANT_CLASS_NAMES) {
                internalNames.add(className.replace('.', '/'));
            }
            importantInternalNames = new HashSet(internalNames);
        }

        public Map getImportantClassLoadingPoints() {
            return importantClassLoadingPoints;
        }

        @Override
        public byte /*@Nullable*/ [] transform(@Nullable ClassLoader loader,
                @Nullable String className, @Nullable Class classBeingRedefined,
                @Nullable ProtectionDomain protectionDomain, byte[] bytes) {
            try {
                if (className == null) {
                    return null;
                }
                if (importantInternalNames.contains(className)
                        || className.equals("java/net/HttpURLConnection")
                        || CHECK_FOR_JUL_LOGGER
                                && className.equals(shadeProofJulLoggerInternalName)) {
                    importantClassLoadingPoints.put(className.replace('/', '.'),
                            new Exception("location stack trace"));
                }
            } catch (Throwable t) {
                if (logger == null) {
                    t.printStackTrace();
                } else {
                    logger.error(t.getMessage(), t);
                }
            }
            return null;
        }

        public static void initLogger() {
            logger = LoggerFactory.getLogger(PreCheckLoadedClasses.class);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy