com.p6spy.engine.spy.P6ModuleManager Maven / Gradle / Ivy
/**
* P6Spy
*
* Copyright (C) 2002 - 2017 P6Spy
*
* 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 com.p6spy.engine.spy;
import com.p6spy.engine.common.P6LogQuery;
import com.p6spy.engine.common.P6Util;
import com.p6spy.engine.spy.option.*;
import javax.management.*;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class P6ModuleManager {
/**
* 修改以引入外部的配置
* add by SUNHAO 2017-12-25
*/
private static final List OPTIONS_SOURCES = new ArrayList<>(16);
private final Map, P6LoadableOptions> allOptions = new HashMap, P6LoadableOptions>();
private final List factories = new CopyOnWriteArrayList();
private final P6MBeansRegistry mBeansRegistry = new P6MBeansRegistry();
private final P6OptionsRepository optionsRepository = new P6OptionsRepository();
private static P6ModuleManager instance;
static {
initMe();
}
private synchronized static void initMe() {
try {
// 修改以引入外部的配置
// add by SUNHAO 2017-12-25
loadP6OptionsSources();
cleanUp();
instance = new P6ModuleManager();
P6LogQuery.initialize();
} catch (IOException e) {
handleInitEx(e);
} catch (MBeanRegistrationException e) {
handleInitEx(e);
} catch (InstanceNotFoundException e) {
handleInitEx(e);
} catch (MalformedObjectNameException e) {
handleInitEx(e);
} catch (NotCompliantMBeanException e) {
handleInitEx(e);
}
}
/**
* 修改以引入外部的配置
* add by SUNHAO 2017-12-25
*/
private static void loadP6OptionsSources() throws IOException {
OPTIONS_SOURCES.add(new SpyDotProperties());
OPTIONS_SOURCES.add(new EnvironmentVariables());
OPTIONS_SOURCES.add(new SystemProperties());
ServiceLoader p6OptionsSources = ServiceLoader.load(P6OptionsSource.class);
for (P6OptionsSource optionsSource : p6OptionsSources) {
OPTIONS_SOURCES.add(optionsSource);
}
}
private static void cleanUp() throws MBeanRegistrationException, InstanceNotFoundException,
MalformedObjectNameException {
if (instance == null) {
return;
}
for (P6OptionsSource optionsSource : P6ModuleManager.OPTIONS_SOURCES) {
optionsSource.preDestroy(instance);
}
if (P6SpyOptions.getActiveInstance().getJmx()) {
// unregister mbeans (to prevent naming conflicts)
if (instance.mBeansRegistry != null) {
instance.mBeansRegistry.unregisterAllMBeans(P6SpyOptions.getActiveInstance().getJmxPrefix());
}
}
// clean table plz (we need to make sure that all the configured factories will be re-loaded)
new DefaultJdbcEventListenerFactory().clearCache();
}
/**
* Used on the class load only (only once!)
*
* @throws IOException
* @throws NotCompliantMBeanException
* @throws MBeanRegistrationException
* @throws InstanceAlreadyExistsException
* @throws MalformedObjectNameException
* @throws InstanceNotFoundException
*/
private P6ModuleManager() throws IOException,
MBeanRegistrationException, NotCompliantMBeanException,
MalformedObjectNameException, InstanceNotFoundException {
debug(this.getClass().getName() + " re/initiating modules started");
// make sure the proper listener registration happens
registerOptionChangedListener(new P6LogQuery());
// hard coded - core module init - as it holds initial config
final P6SpyLoadableOptions spyOptions = (P6SpyLoadableOptions) registerModule(new P6SpyFactory());
loadDriversExplicitly(spyOptions);
// configured modules init
final Set moduleFactories = spyOptions.getModuleFactories();
if (null != moduleFactories) {
for (P6Factory factory : spyOptions.getModuleFactories()) {
registerModule(factory);
}
}
optionsRepository.initCompleted();
mBeansRegistry.registerMBeans(allOptions.values());
for (P6OptionsSource optionsSource : OPTIONS_SOURCES) {
optionsSource.postInit(this);
}
debug(this.getClass().getName() + " re/initiating modules done");
}
private synchronized P6LoadableOptions registerModule(P6Factory factory) {
// re-register is not supported - skip silently
for (P6Factory registeredFactory : factories) {
if (registeredFactory.getClass().equals(factory.getClass())) {
return null;
}
}
final P6LoadableOptions options = factory.getOptions(optionsRepository);
loadOptions(options);
allOptions.put(options.getClass(), options);
factories.add(factory);
debug("Registered factory: " + factory.getClass().getName() + " with options: " + options.getClass().getName());
return options;
}
/**
* Returns loaded options. These are loaded in the right order:
*
* - default values
* - based on the order defined in the {@link #OPTIONS_SOURCES}
*
*
* @param options
* @return
*/
private void loadOptions(final P6LoadableOptions options) {
// make sure to load defaults first
options.load(options.getDefaults());
// load the rest in the right order then
for (P6OptionsSource optionsSource : OPTIONS_SOURCES) {
Map toLoad = optionsSource.getOptions();
if (null != toLoad) {
options.load(toLoad);
}
}
// register to all the props then
allOptions.put(options.getClass(), options);
}
public static P6ModuleManager getInstance() {
return instance;
}
private static void handleInitEx(Exception e) {
e.printStackTrace(System.err);
}
private void loadDriversExplicitly(P6SpyLoadableOptions spyOptions) {
final Collection driverNames = spyOptions.getDriverNames();
if (null != driverNames) {
for (String driverName : driverNames) {
try {
// you really only need to load the driver if it is not a
// type 4 driver!
P6Util.forName(driverName).newInstance();
} catch (Exception e) {
String err = "Error registering driver names: "
+ driverNames + " \nCaused By: " + e.toString();
P6LogQuery.error(err);
throw new P6DriverNotFoundError(err);
}
}
}
}
private void debug(String msg) {
// not initialized yet => nowhere to log yet
if (instance == null || factories.isEmpty()) {
return;
}
P6LogQuery.debug(msg);
}
//
// API methods
//
/**
* @param optionsClass the class to get the options for.
* @return the options instance depending on it's class.
*/
@SuppressWarnings("unchecked")
public T getOptions(Class optionsClass) {
return (T) allOptions.get(optionsClass);
}
/**
* Reloads the {@link P6ModuleManager}.
*
* The idea is that whoever initiates this one causes it to start with the clean table. No
* previously set values are kept (even those set manually - via jmx will be forgotten).
*/
public void reload() {
initMe();
}
public List getFactories() {
return factories;
}
public void registerOptionChangedListener(P6OptionChangedListener listener) {
optionsRepository.registerOptionChangedListener(listener);
}
public void unregisterOptionChangedListener(P6OptionChangedListener listener) {
optionsRepository.unregisterOptionChangedListener(listener);
}
}