/** * Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved. * * 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.springsource.insight.plugin.jdbc; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicBoolean; import com.springsource.insight.intercept.application.ApplicationName; import com.springsource.insight.intercept.operation.Operation; import com.springsource.insight.intercept.operation.OperationType; import com.springsource.insight.intercept.plugin.CollectionSettingName; import com.springsource.insight.intercept.plugin.CollectionSettingsRegistry; import com.springsource.insight.intercept.plugin.CollectionSettingsUpdateListener; import com.springsource.insight.intercept.plugin.names.CollectionSettingNames; import com.springsource.insight.intercept.topology.ExternalResourceDescriptor; import com.springsource.insight.intercept.topology.ExternalResourceType; import com.springsource.insight.intercept.topology.MD5NameGenerator; import com.springsource.insight.intercept.trace.Frame; import com.springsource.insight.intercept.trace.Trace; import com.springsource.insight.util.ListUtil; import com.springsource.insight.util.StringUtil; import com.springsource.insight.util.logging.AbstractLoggingClass; public final class JdbcQueryExternalResourceGenerator extends AbstractLoggingClass implements CollectionSettingsUpdateListener { private final CollectionSettingsRegistry registry; private final Collection<ApplicationName> disabledApps = Collections.synchronizedSet(new TreeSet<ApplicationName>()); private final Collection<ApplicationName> knownApps = Collections.synchronizedSet(new TreeSet<ApplicationName>()); private final AtomicBoolean active = new AtomicBoolean(); private static final class LazyFieldHolder { @SuppressWarnings("synthetic-access") static final JdbcQueryExternalResourceGenerator INSTANCE = new JdbcQueryExternalResourceGenerator(); } public static final JdbcQueryExternalResourceGenerator getInstance() { return LazyFieldHolder.INSTANCE; } private JdbcQueryExternalResourceGenerator() { this(CollectionSettingsRegistry.getInstance()); } // package visibility for unit tests JdbcQueryExternalResourceGenerator(CollectionSettingsRegistry reg) { if ((registry = reg) == null) { throw new IllegalStateException("No registry provide"); } registry.addListener(this); registry.register(CollectionSettingNames.CS_QUERY_EXRTERNAL_RESOURCE_NAME, Boolean.FALSE); } public Collection<ExternalResourceDescriptor> createAndAddQueryExternalResourceDescriptors(Collection<ExternalResourceDescriptor> dbDescriptors, Trace trace) { ApplicationName appName = trace.getAppName(); registerApplicationNameIfNeeded(appName); if (!(active.get() && shouldGenerateQueryExternalResources(dbDescriptors, appName))) { return dbDescriptors; } Collection<ExternalResourceDescriptor> newCollection = new ArrayList<ExternalResourceDescriptor>(dbDescriptors); for (ExternalResourceDescriptor dbDescriptor : dbDescriptors) { Frame frame = dbDescriptor.getFrame(); if (frame == null) { continue; } Operation op = frame.getOperation(); if (op == null) { continue; } String sql = extractSqlFromOperation(op); if (!StringUtil.isEmpty(sql)) { String jdbcHash = MD5NameGenerator.getName(sql); ExternalResourceDescriptor queryDescriptor = new ExternalResourceDescriptor( frame, dbDescriptor.getName() + ":" + jdbcHash, sql, ExternalResourceType.QUERY.name(), dbDescriptor.getVendor(), dbDescriptor.getHost(), dbDescriptor.getPort(), dbDescriptor.getColor(), dbDescriptor.isIncoming(), dbDescriptor); dbDescriptor.setChildren(Collections.singletonList(queryDescriptor)); newCollection.add(queryDescriptor); } } return newCollection; } private boolean shouldGenerateQueryExternalResources(Collection<ExternalResourceDescriptor> dbDescriptors, ApplicationName appName) { if (ListUtil.size(dbDescriptors) == 0) { return false; } return !disabledApps.contains(appName); } private boolean registerApplicationNameIfNeeded(ApplicationName appName) { if (knownApps.add(appName)) { CollectionSettingName name = CollectionSettingNames.createApplicationCollectionSettingName(appName); registry.register(name, Boolean.TRUE); return true; } else { return false; } } public final void incrementalUpdate(CollectionSettingName name, Serializable value) { if ((name == null) || (value == null)) { return; } if (CollectionSettingNames.CS_QUERY_EXRTERNAL_RESOURCE_NAME.equals(name)) { boolean newValue = CollectionSettingsRegistry.getBooleanSettingValue(value); boolean prevValue = active.getAndSet(newValue); if (prevValue != newValue) { _logger.info("incrementalUpdate(" + name + ") " + prevValue + " => " + newValue); } return; } String key = name.getKey(); if (!key.startsWith(CollectionSettingNames.APP_QUERY_EXRTERNAL_RESOURCE_KEY_NAME)) { return; } String appNameStr = key.substring(CollectionSettingNames.APP_QUERY_EXRTERNAL_RESOURCE_KEY_NAME.length()); ApplicationName appName = ApplicationName.valueOf(appNameStr); if (knownApps.add(appName)) { _logger.info("incrementalUpdate(" + appName + ") new application"); } boolean newEnabledValue = CollectionSettingsRegistry.getBooleanSettingValue(value); boolean prevEnabledValue = newEnabledValue ? disabledApps.remove(appName) : disabledApps.add(appName); if (prevEnabledValue != newEnabledValue) { _logger.info("incrementalUpdate(" + appName + ") " + prevEnabledValue + " => " + newEnabledValue); } } public static String extractSqlFromOperation(Operation op) { if (op == null) { return null; } String sql = op.get("sql", String.class); if (!StringUtil.isEmpty(sql)) { return sql; } OperationType type = op.getType(); if (type.equals(JdbcDriverExternalResourceAnalyzer.TYPE)) { return op.getLabel(); } else { return null; } } public boolean isGeneratingExternalResources() { return active.get(); } public boolean isGeneratingExternalResourceForApplication(ApplicationName appName) { return isGeneratingExternalResources() && !disabledApps.contains(appName); } public Collection<ApplicationName> getDisabledApplicationNames() { return Collections.unmodifiableCollection(disabledApps); } public Collection<ApplicationName> getKnownApplicationNames() { return Collections.unmodifiableCollection(knownApps); } public boolean isApplicationNameKnown(ApplicationName appName) { return knownApps.contains(appName); } }