diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java index b5af37e7c..24d3e7ee0 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java @@ -32,6 +32,7 @@ import org.apache.openjpa.event.LifecycleEventManager; import org.apache.openjpa.event.OrphanedKeyAction; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.RemoteCommitProvider; +import org.apache.openjpa.instrumentation.InstrumentationManager; import org.apache.openjpa.kernel.AutoClear; import org.apache.openjpa.kernel.AutoDetach; import org.apache.openjpa.kernel.BrokerFactory; @@ -1836,6 +1837,31 @@ public interface OpenJPAConfiguration * @since 2.0.0 */ public void setCacheDistributionPolicy(String policyPlugin); - + + /** + * Gets the plug-in string that defines instrumentation providers and what + * they instrument. + * @return a plug-in string for the instrumentation configuration + * @since 2.1.0 + */ + public String getInstrumentation(); + + /** + * Sets the plug-in string that defines instrumentation providers and what + * they instrument. + * @param providers a plug-in string for the instrumentation configuration + * @since 2.1.0 + */ + public void setInstrumentation(String providers); + + /** + * Gets an instance of the instrumentation manager. The instrumentation + * provides access to configured instrumentation providers and can be used + * to manage them at runtime. + * @return an instance of the instrumentation manager + * @since 2.1.0 + */ + public InstrumentationManager getInstrumentationManagerInstance(); + } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java index 1596527aa..239ac7a32 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java @@ -36,6 +36,8 @@ import org.apache.openjpa.event.LifecycleEventManager; import org.apache.openjpa.event.OrphanedKeyAction; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.RemoteCommitProvider; +import org.apache.openjpa.instrumentation.InstrumentationManager; +import org.apache.openjpa.instrumentation.InstrumentationManagerImpl; import org.apache.openjpa.kernel.AutoClear; import org.apache.openjpa.kernel.BrokerImpl; import org.apache.openjpa.kernel.ConnectionRetainModes; @@ -61,6 +63,8 @@ import org.apache.openjpa.lib.conf.ProductDerivations; import org.apache.openjpa.lib.conf.StringListValue; import org.apache.openjpa.lib.conf.StringValue; import org.apache.openjpa.lib.encryption.EncryptionProvider; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.instrumentation.InstrumentationProvider; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.meta.MetaDataFactory; @@ -167,6 +171,8 @@ public class OpenJPAConfigurationImpl public StringValue validationGroupPreRemove; public StringValue dataCacheMode; public BooleanValue dynamicEnhancementAgent; + public ObjectValue instrumentationManager; + public PluginListValue instrumentationProviders; // custom values public BrokerFactoryValue brokerFactoryPlugin; @@ -569,6 +575,19 @@ public class OpenJPAConfigurationImpl dynamicEnhancementAgent.setDefault("true"); dynamicEnhancementAgent.set(true); + instrumentationManager = addPlugin("InstrumentationManager", true); + aliases = + new String[] { "default", InstrumentationManagerImpl.class.getName(), }; + instrumentationManager.setAliases(aliases); + instrumentationManager.setDefault(aliases[0]); + instrumentationManager.setString(aliases[0]); + instrumentationManager.setInstantiatingGetter("getInstrumentationManager"); + + instrumentationProviders = addPluginList("Instrumentation"); + aliases = new String[] { "jmx", "org.apache.openjpa.instrumentation.jmx.JMXProvider" }; + instrumentationProviders.setAliases(aliases); + instrumentationProviders.setInstantiatingGetter("getInstrumentationInstances"); + // initialize supported options that some runtimes may not support supportedOptions.add(OPTION_NONTRANS_READ); supportedOptions.add(OPTION_OPTIMISTIC); @@ -1589,6 +1608,46 @@ public class OpenJPAConfigurationImpl return vgPreRemove; } + public String getInstrumentation() { + return instrumentationProviders.getString(); + } + + public void setInstrumentation(String providers) { + instrumentationProviders.setString(providers); + } + + public InstrumentationProvider[] getInstrumentationInstances() { + if (instrumentationProviders.get() == null) + instrumentationProviders.instantiate(InstrumentationProvider.class, this); + return (InstrumentationProvider[]) instrumentationProviders.get(); + } + + public void setInstrumentationManager(String mgr) { + instrumentationManager.setString(mgr); + } + + public String getInstrumentationManager() { + return instrumentationManager.getString(); + } + + public void setInstrumentationManager(InstrumentationManager im) { + if (im != null) + im.initialize(this, instrumentationProviders); + instrumentationManager.set(im); + } + + public InstrumentationManager getInstrumentationManagerInstance() { + InstrumentationManager im = (InstrumentationManager) instrumentationManager.get(); + if (im == null) { + im = (InstrumentationManager) instrumentationManager.instantiate(InstrumentationManager.class, this); + if (im != null) { + im.initialize(this, instrumentationProviders); + im.start(InstrumentationLevel.IMMEDIATE, this); + } + } + return im; + } + public void instantiateAll() { super.instantiateAll(); getMetaDataRepositoryInstance(); @@ -1603,6 +1662,7 @@ public class OpenJPAConfigurationImpl protected void preClose() { ImplHelper.close(metaRepository); ImplHelper.close(remoteEventManager); + ImplHelper.close(getInstrumentationManagerInstance()); super.preClose(); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractDataCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractDataCacheInstrument.java new file mode 100644 index 000000000..dc4d4d1c6 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractDataCacheInstrument.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +import org.apache.openjpa.datacache.CacheStatistics; +import org.apache.openjpa.datacache.DataCache; +import org.apache.openjpa.lib.instrumentation.AbstractInstrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; + +/** + * Provides a basic instrument implementation wrapper for the data cache. This + * class can be extended to create a provider specific instrument for the + * data cache. + */ +public abstract class AbstractDataCacheInstrument extends AbstractInstrument + implements DataCacheInstrument { + + /** + * Value indicating that cache statistics are not available. + */ + public static final long NO_STATS = -1; + + private DataCache _dc = null; + private String _configID = null; + private String _configRef = null; + + public void setDataCache(DataCache dc) { + _dc = dc; + } + + public void setConfigId(String cid) { + _configID = cid; + } + + public void setContextRef(String cref) { + _configRef = cref; + } + + public long getHitCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getHitCount(); + return NO_STATS; + } + + public long getHitCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getHitCount(clazz); + } + + public long getReadCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getReadCount(); + return NO_STATS; + } + + public long getReadCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getReadCount(clazz); + } + + public long getTotalHitCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalHitCount(); + return NO_STATS; + } + + public long getTotalHitCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getTotalHitCount(clazz); + } + + public long getTotalReadCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalReadCount(); + return NO_STATS; + } + + public long getTotalReadCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getTotalReadCount(clazz); + } + + public long getTotalWriteCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalWriteCount(); + return NO_STATS; + } + + public long getTotalWriteCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getTotalWriteCount(clazz); + } + + public long getWriteCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getWriteCount(); + return NO_STATS; + } + + public long getWriteCount(String className) + throws ClassNotFoundException { + Class clazz = Class.forName(className); + return getWriteCount(clazz); + } + + public void reset() { + CacheStatistics stats = getStatistics(); + if (stats != null) + stats.reset(); + } + + public Date sinceDate() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.since(); + return null; + } + + public Date startDate() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.start(); + return null; + } + + public long getEvictionCount() { + CacheStatistics stats = getStatistics(); +// TODO : Implement eviction count in data cache stats +// if (stats != null) +// return stats.getEvictionCount(); + return NO_STATS; + } + + public long getTotalEvictionCount() { + CacheStatistics stats = getStatistics(); + // TODO : Implement eviction count in data cache stats +// if (stats != null) +// return stats.getTotalEvictionCount(); + return NO_STATS; + } + + public String getConfigId() { + return _configID; + } + + public String getContextRef() { + return _configRef; + } + + public String getCacheName() { + if (_dc != null) + return _dc.getName(); + return null; + } + + private CacheStatistics getStatistics() { + if (_dc != null) { + return _dc.getStatistics(); + } + return null; + } + + private long getWriteCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getWriteCount(c); + return NO_STATS; + } + + private long getTotalWriteCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalWriteCount(c); + return NO_STATS; + } + + private long getTotalReadCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalReadCount(c); + return NO_STATS; + } + + private long getTotalHitCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalHitCount(c); + return NO_STATS; + } + + private long getReadCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + stats.getReadCount(c); + return NO_STATS; + } + + private long getHitCount(Class c) { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getHitCount(c); + return NO_STATS; + } + + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } + +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractPreparedQueryCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractPreparedQueryCacheInstrument.java new file mode 100644 index 000000000..8562b565d --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractPreparedQueryCacheInstrument.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +import org.apache.openjpa.kernel.PreparedQueryCache; +import org.apache.openjpa.kernel.QueryStatistics; +import org.apache.openjpa.lib.instrumentation.AbstractInstrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; + +/** + * Provides a basic instrument implementation wrapper for the prepared query cache. This + * class can be extended to create a provider specific instrument for the + * prepared query cache. + */ +public abstract class AbstractPreparedQueryCacheInstrument extends AbstractInstrument + implements PreparedQueryCacheInstrument { + + public static final long NO_STATS = -1; + + private PreparedQueryCache _qc; + private String _configID = null; + private String _configRef = null; + + public void setConfigId(String cid) { + _configID = cid; + } + + public void setContextRef(String cref) { + _configRef = cref; + } + + public String getConfigId() { + return _configID; + } + + public String getContextRef() { + return _configRef; + } + + public void setPreparedQueryCache(PreparedQueryCache qc) { + _qc = qc; + } + + private QueryStatistics getStatistics() { + if (_qc == null) + return null; + return _qc.getStatistics(); + } + + public long getExecutionCount() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getExecutionCount(); + return NO_STATS; + } + + public long getExecutionCount(String query) { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getExecutionCount(query); + return NO_STATS; + } + + public long getTotalExecutionCount() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalExecutionCount(); + return NO_STATS; + } + + public long getTotalExecutionCount(String query) { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalExecutionCount(query); + return NO_STATS; + } + + public long getHitCount() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getHitCount(); + return NO_STATS; + } + + public long getHitCount(String query) { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getHitCount(query); + return NO_STATS; + } + + public long getTotalHitCount() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalHitCount(); + return NO_STATS; + } + + public long getTotalHitCount(String query) { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalHitCount(query); + return NO_STATS; + } + + public void reset() { + QueryStatistics stats = getStatistics(); + if (stats != null) + stats.reset(); + } + + public Date sinceDate() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.since(); + return null; + } + + public Date startDate() { + QueryStatistics stats = getStatistics(); + if (stats != null) + return stats.start(); + return null; + } + + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractQueryCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractQueryCacheInstrument.java new file mode 100644 index 000000000..3b08ad57a --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/AbstractQueryCacheInstrument.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +import org.apache.openjpa.datacache.CacheStatistics; +import org.apache.openjpa.datacache.QueryCache; +import org.apache.openjpa.lib.instrumentation.AbstractInstrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; + +/** + * Provides a basic instrument implementation wrapper for the query cache. This + * class can be extended to create a provider specific instrument for the + * query cache. + */ +public abstract class AbstractQueryCacheInstrument extends AbstractInstrument + implements QueryCacheInstrument { + + /** + * Value indicating that cache statistics are not available. + */ + public static final long NO_STATS = -1; + + private QueryCache _qc; + private String _configId = null; + private String _configRef = null; + + public void setQueryCache(QueryCache qc) { + _qc = qc; + } + + // TODO : Cache stats must be added to query cache. They will likely be + // tracked by a QueryStatistics type when that takes place. + private CacheStatistics getStatistics() { + if (_qc == null) + return null; + return null; // _qc.getStatistics(); + } + + public long getHitCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getHitCount(); + return NO_STATS; + } + + public long getReadCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getReadCount(); + return NO_STATS; + } + + public long getTotalHitCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalHitCount(); + return NO_STATS; + } + + public long getTotalReadCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalReadCount(); + return NO_STATS; + } + + public long getTotalWriteCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getTotalWriteCount(); + return NO_STATS; + } + + public long getWriteCount() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.getWriteCount(); + return NO_STATS; + } + + public void reset() { + CacheStatistics stats = getStatistics(); + if (stats != null) + stats.reset(); + } + + public Date sinceDate() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.since(); + return null; + } + + public Date startDate() { + CacheStatistics stats = getStatistics(); + if (stats != null) + return stats.start(); + return null; + } + + public String getConfigId() { + return _configId; + } + + public void setConfigId(String cid) { + _configId = cid; + } + + public String getContextRef() { + return _configRef; + } + + public void setContextRef(String cref) { + _configRef = cref; + } + + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } + +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrument.java new file mode 100644 index 000000000..ad8166180 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrument.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +/** + * Interface for providing instrumented data cache metrics and operations. + */ +public interface DataCacheInstrument { + + /** + * Gets number of total read requests for the given class since last reset. + */ + public long getReadCount(String className) throws ClassNotFoundException; + + /** + * Gets number of total read requests that has been found in cache for the + * given class since last reset. + */ + public long getHitCount(String className) throws ClassNotFoundException; + + /** + * Gets number of total write requests for the given class since last reset. + */ + public long getWriteCount(String className) throws ClassNotFoundException; + + /** + * Gets number of total read requests for the given class since start. + */ + public long getTotalReadCount(String className) + throws ClassNotFoundException; + + /** + * Gets number of total read requests that has been found in cache for the + * given class since start. + */ + public long getTotalHitCount(String className) + throws ClassNotFoundException; + + /** + * Gets number of total write requests for the given class since start. + */ + public long getTotalWriteCount(String className) + throws ClassNotFoundException; + + /** + * Gets the number of cache evictions from the last reset. + */ + public long getEvictionCount(); + + /** + * Gets the total number of cache evictions since cache start. + */ + public long getTotalEvictionCount(); + + /** + * Returns the name of the cache + */ + public String getCacheName(); + + /** + * Returns the hit count since cache statistics were last reset + */ + public long getHitCount(); + + /** + * Returns the read count since cache statistics were last reset + */ + public long getReadCount(); + + /** + * Returns the total hits since start. + */ + public long getTotalHitCount(); + + /** + * Returns the total reads since start. + */ + public long getTotalReadCount(); + + /** + * Returns the total writes since start. + */ + public long getTotalWriteCount(); + + /** + * Returns the write count since cache statistics were last reset + */ + public long getWriteCount(); + + /** + * Resets cache statistics + */ + public void reset(); + + /** + * Returns date since cache statistics collection were last reset. + */ + public Date sinceDate(); + + /** + * Returns date cache statistics collection started. + */ + public Date startDate(); +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrumentMBean.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrumentMBean.java new file mode 100644 index 000000000..3e32b5c6d --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/DataCacheInstrumentMBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +/** + * Simple MBean interface for providing instrumented data cache metrics + * and operations. + * Note: Simple MBeans require an MBean interface matching the supplied + * implementation class. + */ +public interface DataCacheInstrumentMBean + extends DataCacheInstrument { + +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManager.java new file mode 100644 index 000000000..c2ce1c658 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManager.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Set; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.lib.conf.PluginListValue; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.instrumentation.InstrumentationProvider; +import org.apache.openjpa.lib.util.Closeable; + +/** + * Managers of instrumentation providers must implement this interface. It + * provides methods for initializing multiple providers via configuration in + * addition to managing instrumentation providers and the state of the providers. + */ +public interface InstrumentationManager extends Closeable { + + /** + * Used to initialize one or more providers using the supplied configuration. + * @param conf the configuration to use for initialization + * @param providers one or more providers as supplied via plugin list value + */ + public void initialize(OpenJPAConfiguration conf, PluginListValue providers); + + /** + * Manage a given provider. This will plug the instruments managed by the + * the provider into the life cycle of the manager + * @param provider the instrumentation provider + */ + public void manageProvider(InstrumentationProvider provider); + + /** + * Starts all instruments for all managed providers for a given level + * and context. + * @param level instrumentation level + * @param context instrumentation context (broker, factory, config,...) + */ + public void start(InstrumentationLevel level, Object context); + + /** + * Stops all instruments for all managed providers for a given level + * and context. + * @param level instrumentation level + * @param context instrumentation context (broker, factory, config,...) + */ + public void stop(InstrumentationLevel broker, Object context); + + /** + * Returns all providers managed by this manager. + * @return all providers managed by this manager + */ + public Set getProviders(); +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManagerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManagerImpl.java new file mode 100644 index 000000000..2192aeb53 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/InstrumentationManagerImpl.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.lib.conf.PluginListValue; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.instrumentation.InstrumentationProvider; + +/** + * An implementation of an instrumentation manager. + */ +public class InstrumentationManagerImpl implements InstrumentationManager { + + public Set _providers = + Collections.synchronizedSet(new HashSet()); + + private boolean _closed = false; + + /** + * Initializes all providers defined for the specified configuration. + * @param conf + * @param providers + */ + public void initialize(OpenJPAConfiguration conf, PluginListValue pluginVal) { + InstrumentationProvider[] providers = + (InstrumentationProvider[])pluginVal.instantiate(InstrumentationProvider.class, conf); + _providers.addAll(Arrays.asList(providers)); + } + + /** + * Make a provider managed. This will bind its instrumentation to + * InstrumentationLevel type events (factory create/close, broker create/close). + * @param provider + * @param config + */ + public void manageProvider(InstrumentationProvider provider) { + _providers.add(provider); + } + + /** + * Returns all providers as an unmodifiable set + */ + public Set getProviders() { + return Collections.unmodifiableSet(_providers); + } + + /** + * Starts all providers at a specific level and context + */ + public void start(InstrumentationLevel level, Object context) { + if (_providers == null || _providers.size() == 0) { + return; + } + for (InstrumentationProvider provider : _providers) { + if (!provider.isStarted()) { + provider.start(); + } + provider.startInstruments(level, context); + } + } + + /** + * Stops all providers at a specific level and context + */ + public void stop(InstrumentationLevel level, Object context) { + if (_providers == null || _providers.size() == 0) { + return; + } + for (InstrumentationProvider provider : _providers) { + provider.stopInstruments(level, context); + } + } + + /** + * Stops all providers + */ + public void close() throws Exception { + if (_closed) { + return; + } + for (InstrumentationProvider provider : _providers) { + provider.stop(); + } + _closed = true; + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrument.java new file mode 100644 index 000000000..a8be389e0 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrument.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +public interface PreparedQueryCacheInstrument { + + /** + * Returns number of total exec requests since start. + */ + public long getTotalExecutionCount(); + + /** + * Returns number of total exec requests since start. + */ + public long getTotalExecutionCount(String query); + + /** + * Returns number of total execution requests since last reset + */ + public long getExecutionCount(); + + /** + * Returns number of total execution requests since last reset + */ + public long getExecutionCount(String query); + + /** + * Returns number of total read requests that have been found in cache since + * last reset. + */ + public long getHitCount(); + + /** + * Returns number of total read requests that have been found in cache since + * last reset. + */ + public long getHitCount(String query); + + /** + * Returns number of total read requests that has been found since start. + */ + public long getTotalHitCount(); + + /** + * Returns number of total read requests that has been found since start. + */ + public long getTotalHitCount(String query); + + /** + * Returns the config id for the configuration attached to this cache + */ + public String getConfigId(); + + /** + * Returns the context unique id for the configuration attached to this + * cache + */ + public String getContextRef(); + + /** + * Resets cache statistics + */ + public void reset(); + + /** + * Returns date since cache statistics collection were last reset. + */ + public Date sinceDate(); + + /** + * Returns date cache statistics collection started. + */ + public Date startDate(); +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrumentationMBean.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrumentationMBean.java new file mode 100644 index 000000000..f47eabb62 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/PreparedQueryCacheInstrumentationMBean.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +public interface PreparedQueryCacheInstrumentationMBean + extends PreparedQueryCacheInstrument { + +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrument.java new file mode 100644 index 000000000..9788acf49 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrument.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Date; + +/** + * Interface for providing instrumented data cache metrics and operations. + */ +public interface QueryCacheInstrument { + + /** + * Returns number of total read requests that have been found in cache since + * last reset. + */ + public long getHitCount(); + + /** + * Returns number of total read requests since last reset + */ + public long getReadCount(); + + /** + * Returns number of total write requests since last reset. + */ + public long getWriteCount(); + + /** + * Returns number of total read requests since start. + */ + public long getTotalReadCount(); + + /** + * Returns number of total read requests that has been found since start. + */ + public long getTotalHitCount(); + + /** + * Returns number of total write requests for the given class since start. + */ + public long getTotalWriteCount(); + + /** + * Returns the config id for the configuration attached to this cache + */ + public String getConfigId(); + + /** + * Returns the system unique id for the configuration attached to this + * cache + */ + public String getContextRef(); + + /** + * Resets cache statistics + */ + public void reset(); + + /** + * Returns date since cache statistics collection were last reset. + */ + public Date sinceDate(); + + /** + * Returns date cache statistics collection started. + */ + public Date startDate(); +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrumentMBean.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrumentMBean.java new file mode 100644 index 000000000..904f7cd52 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/QueryCacheInstrumentMBean.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +/** + * Simple MBean interface for providing instrumented query cache metrics + * and operations. + * Note: Simple MBeans require an MBean interface matching the supplied + * implementation class. + */ +public interface QueryCacheInstrumentMBean extends QueryCacheInstrument { + +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/DataCacheJMXInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/DataCacheJMXInstrument.java new file mode 100644 index 000000000..9d7d2b47c --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/DataCacheJMXInstrument.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation.jmx; + +import javax.management.ObjectName; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.datacache.DataCache; +import org.apache.openjpa.datacache.DataCacheManager; +import org.apache.openjpa.instrumentation.AbstractDataCacheInstrument; +import org.apache.openjpa.lib.conf.Configurations; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.lib.util.Options; +import org.apache.openjpa.util.UserException; + +/** + * A JMX-specific instrument for the data cache + */ +public class DataCacheJMXInstrument extends AbstractDataCacheInstrument + implements JMXInstrument { + + private static Localizer _loc = Localizer.forPackage(DataCacheJMXInstrument.class); + + private static final String MBEAN_TYPE = "DataCache"; + private ObjectName _objName = null; + + @Override + public String getName() { + return MBEAN_TYPE; + } + + @Override + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } + + @Override + public void initialize() { + Options opts = new Options(); + if (getOptions() != null) { + opts = Configurations.parseProperties(getOptions()); + } + + String cacheName = opts.getProperty("name",null); + OpenJPAConfiguration conf = (OpenJPAConfiguration)getProvider().getConfiguration(); + DataCacheManager dcm = conf.getDataCacheManagerInstance(); + DataCache dc = null; + if (cacheName == null || cacheName.trim().length() == 0) { + dc = dcm.getSystemDataCache(); + } else { + dc = dcm.getDataCache(cacheName); + } + if (dc == null) { + throw new UserException(_loc.get("data-cache-not-found")); + } + + setDataCache(dc); + setConfigId(conf.getId()); + setContextRef(Integer.toString(System.identityHashCode(getContext()))); + } + + public ObjectName getObjectName() { + if (_objName != null) { + return _objName; + } + + try { + _objName = JMXProvider.createObjectName(this, null); + return _objName; + } catch (Throwable t) { + throw new UserException(_loc.get("unable-to-create-object-name", getName()), t); + } + } + + public void start() { + getProvider().startInstrument(this); + } + + public void stop() { + getProvider().stopInstrument(this); + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXInstrument.java new file mode 100644 index 000000000..6a3e1e4ef --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXInstrument.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation.jmx; + +import javax.management.ObjectName; + +import org.apache.openjpa.lib.instrumentation.Instrument; + +/** + * Interface for JMX-specific instruments + */ +public interface JMXInstrument extends Instrument { + + /** + * Returns the JMX object name for the instrument + * @return + */ + public ObjectName getObjectName(); + + /** + * Sets the context reference for the instrument. Required to register + * the instrument under a unique id. + * @param cref the context reference for the instrument + */ + public void setContextRef(String cref); + + /** + * Gets the context reference for the instrument. Required to register + * the instrument under a unique id. + * @param cref the context reference for the instrument + */ + public String getContextRef(); + + /** + * Sets the config id for the instrument. Required to register + * the instrument under a unique id. + * @return the config id of the instrument + */ + public String getConfigId(); + + /** + * Gets the config id for the instrument. Required to register + * the instrument under a unique id. + * @param cid the config id of the instrument + */ + public void setConfigId(String cid); +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXProvider.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXProvider.java new file mode 100644 index 000000000..a91a35c95 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/JMXProvider.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation.jmx; + +import java.lang.management.ManagementFactory; +import java.util.Map; +import java.util.Map.Entry; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.openjpa.lib.instrumentation.AbstractInstrumentationProvider; +import org.apache.openjpa.lib.instrumentation.Instrument; +import org.apache.openjpa.util.UserException; + +/** + * A simple MBean JMX instrumentation provider + */ +public class JMXProvider + extends AbstractInstrumentationProvider { + + // Aliases for built-in JMX Instrumentation + public static final String[] JMX_INSTRUMENT_ALIASES = { + "DataCache", "org.apache.openjpa.instrumentation.jmx.DataCacheJMXInstrument", + "QueryCache", "org.apache.openjpa.insrumentation.jmx.QueryCacheJMXInstrument", + "QuerySQLCache", "org.apache.openjpa.insrumentation.jmx.PreparedQueryCacheJMXInstrument" + }; + + /** + * The standard mbean package for OpenJPA + */ + public static final String MBEAN_PACKAGE = "org.apache.openjpa"; + + private MBeanServer _mbs = null; + + /** + * Register an MBean with the mbean server. + * @param mBean + */ + protected void registerMBean(JMXInstrument mBean) { + MBeanServer mbs = getMBeanServer(); + try { + mbs.registerMBean(mBean, mBean.getObjectName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the mbean server + * @return + */ + public MBeanServer getMBeanServer() { + if (_mbs == null) { + _mbs = ManagementFactory.getPlatformMBeanServer(); + } + return _mbs; + } + + @Override + public void start() { + try { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) { + throw new UserException("jmx-server-failed-creation"); + } + } catch (Throwable t) { + throw new UserException("jmx-server-unavailable",t); + } + } + + @Override + public void stop() { + // no-op with the built in MBean server + } + + /** + * Creates an object name for the supplied instrument and key properties + * @param instrument the instrument + * @param props additional key properties + * @return the JMX object name + * @throws Exception a generic JMX-type exception + */ + public static ObjectName createObjectName(JMXInstrument instrument, Map props) + throws Exception { + // Construct the base name + StringBuilder sbName = new StringBuilder(MBEAN_PACKAGE); + sbName.append("type="); + sbName.append(instrument.getName()); + sbName.append(",cfgid="); + sbName.append(instrument.getConfigId()); + sbName.append(",cfgref="); + sbName.append(instrument.getContextRef()); + // Add any additional key properties that were provided + if (props != null && !props.isEmpty()) { + for (Entry prop : props.entrySet()) { + sbName.append(","); + sbName.append(prop.getKey()); + sbName.append("="); + sbName.append(prop.getValue()); + } + } + return new ObjectName(sbName.toString()); + } + + /** + * Start an instrument. Registers an mbean with the server. + */ + public void startInstrument(Instrument instrument) { + if (!instrument.isStarted()) { + registerMBean((JMXInstrument)instrument); + } + } + + /** + * Stop an instrument. Unregisters an mbean with the server. + */ + public void stopInstrument(Instrument instrument, boolean force) { + if (instrument.isStarted() || force) { + try { + getMBeanServer().unregisterMBean(((JMXInstrument)instrument).getObjectName()); + } catch (Exception e) { + // If force, swallow the exception since the bean may not even + // be registered. + if (!force) { + throw new UserException("cannot-stop-instrument",e); + } + } + } + } + + /** + * Returns aliases for built-in instruments. + */ + @Override + public String[] getInstrumentAliases() { + return JMX_INSTRUMENT_ALIASES; + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/PreparedQueryCacheJMXInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/PreparedQueryCacheJMXInstrument.java new file mode 100644 index 000000000..d80cbbdc5 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/PreparedQueryCacheJMXInstrument.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation.jmx; + +import javax.management.ObjectName; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.instrumentation.AbstractPreparedQueryCacheInstrument; +import org.apache.openjpa.kernel.PreparedQueryCache; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.util.UserException; + +/** + * A JMX-specific instrument for the query cache + */ +public class PreparedQueryCacheJMXInstrument extends AbstractPreparedQueryCacheInstrument + implements JMXInstrument { + + private static Localizer _loc = Localizer.forPackage(PreparedQueryCacheJMXInstrument.class); + + private static final String MBEAN_TYPE = "QuerySQLCache"; + + private ObjectName _objName = null; + + @Override + public String getName() { + return MBEAN_TYPE; + } + + @Override + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } + + + @Override + public void initialize() { + + OpenJPAConfiguration conf = (OpenJPAConfiguration)getProvider().getConfiguration(); + PreparedQueryCache pqc = conf.getQuerySQLCacheInstance(); + + if (pqc == null) { + throw new UserException(_loc.get("prep-query-cache-not-found")); + } + + setPreparedQueryCache(pqc); + setConfigId(conf.getId()); + setContextRef(Integer.toString(System.identityHashCode(getContext()))); + } + + public ObjectName getObjectName() { + if (_objName != null) { + return _objName; + } + + try { + _objName = JMXProvider.createObjectName(this, null); + return _objName; + } catch (Throwable t) { + throw new UserException(_loc.get("unable-to-create-object-name", getName()), t); + } + } + + public void start() { + getProvider().startInstrument(this); + } + + public void stop() { + getProvider().stopInstrument(this); + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/QueryCacheJMXInstrument.java b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/QueryCacheJMXInstrument.java new file mode 100644 index 000000000..cdee28c55 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/instrumentation/jmx/QueryCacheJMXInstrument.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation.jmx; + +import javax.management.ObjectName; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.datacache.DataCacheManager; +import org.apache.openjpa.datacache.QueryCache; +import org.apache.openjpa.instrumentation.AbstractQueryCacheInstrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; +import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.util.UserException; + +/** + * A JMX-specific instrument for the query cache + */ +public class QueryCacheJMXInstrument extends AbstractQueryCacheInstrument + implements JMXInstrument { + + private static Localizer _loc = Localizer.forPackage(QueryCacheJMXInstrument.class); + + private static final String MBEAN_TYPE = "QueryCache"; + private ObjectName _objName = null; + + @Override + public String getName() { + return MBEAN_TYPE; + } + + @Override + public InstrumentationLevel getLevel() { + return InstrumentationLevel.FACTORY; + } + + + @Override + public void initialize() { + + OpenJPAConfiguration conf = (OpenJPAConfiguration)getProvider().getConfiguration(); + DataCacheManager dcm = conf.getDataCacheManagerInstance(); + QueryCache qc = dcm.getSystemQueryCache(); + + if (qc == null) { + throw new UserException(_loc.get("query-cache-not-found")); + } + + setQueryCache(qc); + setConfigId(conf.getId()); + setContextRef(Integer.toString(System.identityHashCode(getContext()))); + } + + public ObjectName getObjectName() { + if (_objName != null) { + return _objName; + } + + try { + _objName = JMXProvider.createObjectName(this, null); + return _objName; + } catch (Throwable t) { + throw new UserException(_loc.get("unable-to-create-object-name", getName()), t); + } + } + + public void start() { + getProvider().startInstrument(this); + } + + public void stop() { + getProvider().stopInstrument(this); + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java index 38ad3ce8d..84b2477c5 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java @@ -53,8 +53,10 @@ import org.apache.openjpa.enhance.PCRegistry; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.event.BrokerFactoryEvent; import org.apache.openjpa.event.RemoteCommitEventManager; +import org.apache.openjpa.instrumentation.InstrumentationManager; import org.apache.openjpa.lib.conf.Configuration; import org.apache.openjpa.lib.conf.Configurations; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; @@ -868,6 +870,12 @@ public abstract class AbstractBrokerFactory // Get a DataCacheManager instance up front to avoid threading concerns on first call. // _conf.getDataCacheManagerInstance(); + + InstrumentationManager imgr = _conf.getInstrumentationManagerInstance(); + if (imgr != null) { + // Start all factory level instrumentation + imgr.start(InstrumentationLevel.FACTORY, this); + } } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index d87ae81b7..febbfccd6 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -62,8 +62,10 @@ import org.apache.openjpa.event.LifecycleEventManager; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.TransactionEvent; import org.apache.openjpa.event.TransactionEventManager; +import org.apache.openjpa.instrumentation.InstrumentationManager; import org.apache.openjpa.kernel.exps.ExpressionParser; import org.apache.openjpa.lib.conf.Configurations; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; @@ -170,6 +172,7 @@ public class BrokerImpl private transient ReentrantLock _lock = null; private transient OpCallbacks _call = null; private transient RuntimeExceptionTranslator _extrans = null; + private transient InstrumentationManager _instm = null; // ref to producing factory and configuration private transient AbstractBrokerFactory _factory = null; @@ -366,6 +369,11 @@ public class BrokerImpl _fc = _store.newFetchConfiguration(); _fc.setContext(this); } + + _instm = _conf.getInstrumentationManagerInstance(); + if (_instm != null) { + _instm.start(InstrumentationLevel.BROKER, this); + } // synch with the global transaction in progress, if any if (_factory.syncWithManagedTransaction(this, false)) @@ -4348,6 +4356,9 @@ public class BrokerImpl _lm.close(); _store.close(); + if (_instm != null) { + _instm.stop(InstrumentationLevel.BROKER, this); + } _flags = 0; _closed = true; if (_log.isTraceEnabled()) diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/instrumentation/jmx/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/instrumentation/jmx/localizer.properties new file mode 100644 index 000000000..95cc6863f --- /dev/null +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/instrumentation/jmx/localizer.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +data-cache-not-found: A data cache instance could not be located by the instrumentation. \ + Ensure the data cache is properly configured and available. +query-cache-not-found: A query cache instance could not be located by the instrumentation. \ + Ensure the query cache is properly configured and available. +unable-to-create-object-name: Error while attempting to create JMX object name for "{0}". \ + See nested exception for details. +jmx-server-failed-creation: The JMX server could not be created. +jmx-server-unavailable: The JMX server is not available. See nested exception for details. +cannot-stop-instrument: Unable to stop JMX instrument. Instrument may not have been \ + started or may not be responding. See nested exception for details. +prep-query-cache-not-found: A data cache instance could not be located by the instrumentation. \ + Ensure the prepared query cache (QuerySQLCache) is properly configured and available. \ No newline at end of file diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrument.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrument.java new file mode 100644 index 000000000..b9c89019f --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrument.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.lib.instrumentation; + +/** + * Provides a base for creating instruments. Specialized instruments can + * extend this class to get base instrument capabilities and then add their + * own specialized functionality. + */ +public abstract class AbstractInstrument implements Instrument { + + private boolean _started = false; + private InstrumentationProvider _provider; + private Object _context; + private String _options; + + public Object getContext() { + return _context; + } + + public void setContext(Object context) { + _context = context; + } + + public String getOptions() { + return _options; + } + + public void setOptions(String options) { + _options = options; + } + + public boolean isStarted() { + return _started; + } + + public void setStarted(boolean started) { + _started = started; + } + + public void restart() { + stop(); + start(); + } + + public void setProvider(InstrumentationProvider provider) { + _provider = provider; + } + + public InstrumentationProvider getProvider() { + return _provider; + } + + public InstrumentationLevel getLevel() { + return InstrumentationLevel.MANUAL; + } + + public abstract String getName(); + + public abstract void initialize(); +} diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrumentationProvider.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrumentationProvider.java new file mode 100644 index 000000000..8c8b36941 --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/AbstractInstrumentationProvider.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.lib.instrumentation; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.openjpa.lib.conf.Configurable; +import org.apache.openjpa.lib.conf.Configuration; +import org.apache.openjpa.lib.conf.PluginListValue; + +/** + * Specialized instrumentation providers can extend this class to get basic + * provider state and capabilities. It implements Configurable so it can + * be used within the configuration framework to participate in automatic + * configuration. + */ +public abstract class AbstractInstrumentationProvider implements InstrumentationProvider, Configurable { + + private Map _instruments = new ConcurrentHashMap(); + + private boolean _started = false; + private PluginListValue _instrumentValues; + private String _options; + private Configuration _config; + + public void setConfiguration(Configuration conf) { + _config = conf; + } + + public Configuration getConfiguration() { + return _config; + } + + public void startConfiguration() { + } + + public void endConfiguration() { + } + + public void setInstrument(String instrument) { + _instrumentValues = new PluginListValue("Instrument"); + if (getInstrumentAliases() != null) { + _instrumentValues.setAliases(getInstrumentAliases()); + } + _instrumentValues.setString(instrument); + + Instrument[] instruments = (Instrument[])_instrumentValues.instantiate(Instrument.class, _config); + for (Instrument inst : instruments) { + inst.setProvider(this); + _instruments.put(inst.getName(), inst); + } + } + + public String getInstrument() { + return _instrumentValues.getString(); + } + + public void setOptions(String options) { + _options = options; + } + + public String getOptions() { + return _options; + } + + public void addInstrument(Instrument instrument) { + if (instrument == null) { + return; + } + instrument.setProvider(this); + _instruments.put(instrument.getName(), instrument); + } + + public void initializeInstrument(Instrument instrument, Object context) { + initializeInstrument(instrument, _options, context); + } + + public void initializeInstrument(Instrument instrument, String options, Object context) { + instrument.setProvider(this); + instrument.setOptions(options); + instrument.setContext(context); + instrument.initialize(); + } + + public Instrument getInstrumentByName(String name) { + return _instruments.get(name); + } + + public Set getInstruments() { + return new HashSet(_instruments.values()); + } + + public void stopInstruments(InstrumentationLevel level, Object context) { + try { + Set instruments = getInstruments(); + for (Instrument instrument : instruments) { + if (instrument.getLevel() == level && + contextEquals(instrument.getContext(),context)) { + stopInstrument(instrument); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void startInstruments(InstrumentationLevel level, Object context) { + Set instruments = getInstruments(); + for (Instrument instrument : instruments) { + if (instrument.getLevel() == level) { + initializeInstrument(instrument, context); + startInstrument(instrument); + } + } + } + + public void stopInstrument(Instrument instrument) { + stopInstrument(instrument, true); + } + + public void removeInstrumentByName(String name) { + Instrument ins = _instruments.remove(name); + if (ins != null) { + ins.stop(); + } + } + + public boolean isStarted() { + return _started; + } + + protected void setStarted(boolean started) { + _started = started; + } + + public String[] getInstrumentAliases() { + return null; + } + + public abstract void start(); + + public abstract void stop(); + + private static boolean contextEquals(Object ctx1, Object ctx2) { + if (ctx1 == ctx2) { + return true; + } + if (ctx1 == null) { + return false; + } + return ctx1.equals(ctx2); + } + +} diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/Instrument.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/Instrument.java new file mode 100644 index 000000000..bc16b1ef0 --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/Instrument.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.lib.instrumentation; + +/** + * Interface that must be implemented by instruments. + */ +public interface Instrument { + + /** + * Returns the name of the instrument. Must be unique per-provider. + */ + public String getName(); + + /** + * Returns the options specified for the instrument in string form. + * @return options configuration options for the instrument + */ + public String getOptions(); + + /** + * Sets options to specify for the instrument in standard string form. + * ex. DataCache(Options='Start=true') + * @param options options + */ + public void setOptions(String options); + + /** + * Gets the context of the instrument. Typically, a reference to a broker + * or broker factory. + * @return the context associated with the instrument. + */ + public Object getContext(); + + /** + * Sets the context of the instrument. Typically, a reference to a broker + * or broker factory. + * @return the context associated with the instrument. + */ + public void setContext(Object context); + + /** + * Sets the instrumentation provider for the instrument. + * @param provider instrumentation provider of the instrument + */ + public void setProvider(InstrumentationProvider provider); + + /** + * Gets the instrumentation provider for the instrument. + * @return instrumentation provider of the instrument + */ + public InstrumentationProvider getProvider(); + + /** + * Initializes the instrument. Depending on the instrument, the provider, + * options, and various options may need to be set before calling this method. + */ + public void initialize(); + + /** + * Gets the instrumentation level of this instrument. The instrumentation level + * determines if and when the instrument will automatically start and stop. + * @return the instrumentation level of the instrument + */ + public InstrumentationLevel getLevel(); + + /** + * Returns true if the instrument is started. + * @return + */ + public boolean isStarted(); + + /** + * Starts the instrument. Typically this will be performed through the provider, + * but in some cases an instrument will have its own specialized startup. + */ + public void start(); + + /** + * Starts the instrument. Typically this will be performed through the provider, + * but in some cases an instrument will have its own specialized shutdown. + */ + public void stop(); + + /** + * Restarts the instrument. Typically this will be performed through the provider, + * but in some cases an instrument will have its own specialized restart. + */ + public void restart(); +} diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationLevel.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationLevel.java new file mode 100644 index 000000000..2b4bd78ca --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationLevel.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.lib.instrumentation; + +/** + * The instrumentation level can be used to indicate if and when an instrument will be + * automatically started and stopped. + * + */ +public enum InstrumentationLevel { + /** + * Start immediately (no special requirements on the broker or factory) and + * stop when the configuration is closed. + */ + IMMEDIATE, + /** + * Start following factory initialization and stop when the factory is closed. + */ + FACTORY, + /** + * Start following broker/em initialization and stop when the broker/em is closed. + */ + BROKER, + /** + * Manual start and stop. + */ + MANUAL +} diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationProvider.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationProvider.java new file mode 100644 index 000000000..4ae2fbe93 --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/instrumentation/InstrumentationProvider.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.lib.instrumentation; + +import java.util.Set; + +import org.apache.openjpa.lib.conf.Configuration; + +/** + * Pluggable instrumentation providers (ex. JMX) must implement this interface. It + * provides methods for controlling the provider and the instruments instrumented + * by the provider. + */ +public interface InstrumentationProvider { + + /** + * Whether the instrumentation provider started + * @return true if the provider is started + */ + public boolean isStarted(); + /** + * Starts the instrumentation provider + */ + public void stop(); + + /** + * Stops the instrumentation provider + */ + public void start(); + + /** + * Gets the configuration associated with the instrumentation provider + * @return the configuration associated with the provider + */ + public Configuration getConfiguration(); + + /** + * Used to associate one or more instruments to a provider. Instruments + * are specified by class name or alias. Multiple instruments must be + * specified as a comma separated list. + * + * example: DataCache,QueryCache,com.my.MyInstrument + * where DataCache and QueryCache have aliases and com.my.MyInstrument is + * a class implementing an Instrument. + * + * @param instruments one or more instrument class names or aliases + */ + public void setInstrument(String instruments); + + /** + * Returns the string-based list of instruments directly configured by + * this provider via setInstrument. + * @return + */ + public String getInstrument(); + + /** + * Sets configuration options for this provider + * @param options + */ + public void setOptions(String options); + + /** + * Gets configuration options for this provider + * @param options + */ + public String getOptions(); + + /** + * Returns an string array of identifier to class name aliases for + * instruments known to the instrumentation provider. Example: + * + * {"DataCache", "org.apache.openjpa.instrumentation.DataCacheInstrument", + * "QueryCache", "org.apache.openjpa.instrumentation.QueryCacheInstrument"} + * @return a string array of identifier, class name pairs. + */ + public String[] getInstrumentAliases(); + + /** + * Adds an instrument to this providers list of managed instruments. The + * instrument will participate in context-based lifecycle routines, + * depending on the instrumentation level. + * @param instrument + */ + public void addInstrument(Instrument instrument); + + /** + * Stops all instruments of the specified instrumentation level and context. + * @param level instrumentation level + * @param context instrumentation context (factory, broker, config) + */ + public void stopInstruments(InstrumentationLevel level, Object context); + + /** + * Starts all instruments of the specified instrumentation level and context. + * @param level instrumentation level + * @param context instrumentation context (factory, broker, config) + */ + public void startInstruments(InstrumentationLevel level, Object context); + + /** + * Initializes an instrument within the provided context. + * @param instrument an instrument + * @param context instrumentation context (factory, broker, config) + */ + public void initializeInstrument(Instrument instrument, Object context); + + /** + * Initializes an instrument within the provided options and context. + * @param instrument an instrument + * @param options configuration options to provide the instrument during initialization + * @param context instrumentation context (factory, broker, config) + */ + public void initializeInstrument(Instrument instrument, String options, Object context); + + /** + * Returns an instrument instrumented by this provider by name + * @param name the name of the instrument to return + * @return the instrument or null if not instrumented by this provider + */ + public Instrument getInstrumentByName(String name); + + /** + * Removes an instrument instrumented by this provider by name + * @param name the name of the instrument to remove + */ + public void removeInstrumentByName(String name); + + /** + * Gets all instruments instrumented by this provider + * @return instruments instrumented by this provider + */ + public Set getInstruments(); + + /** + * Starts an instrument + * @param instrument this instrument to start + */ + public void startInstrument(Instrument instrument); + + /** + * Stops an instrument + * @param instrument the instrument to stop + */ + public void stopInstrument(Instrument instrument); + + /** + * Stops an instrument, forcing the stop, if necessary. + * @param instrument the instrument to stop + * @param force forces the stop if the instrument does not stop gracefully. + */ + public void stopInstrument(Instrument instrument, boolean force); +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/BrokerLevelInstrument.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/BrokerLevelInstrument.java new file mode 100644 index 000000000..335c1c404 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/BrokerLevelInstrument.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.lib.instrumentation.AbstractInstrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationLevel; + +public class BrokerLevelInstrument extends AbstractInstrument { + + public static String NAME = "NoneInstrument"; + + private boolean _initialized; + + @Override + public String getName() { + return NAME; + } + + @Override + public void initialize() { + setInitialized(true); + } + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + } + + public InstrumentationLevel getLevel() { + return InstrumentationLevel.BROKER; + } + + public void setInitialized(boolean _initialized) { + this._initialized = _initialized; + } + + public boolean isInitialized() { + return _initialized; + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DCInstrument.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DCInstrument.java new file mode 100644 index 000000000..f4ffa2683 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DCInstrument.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.conf.OpenJPAConfiguration; + +public class DCInstrument extends AbstractDataCacheInstrument { + + public static final String NAME = "SimpleDCInstrument"; + + @Override + public String getName() { + return NAME; + } + + public void initialize() { + OpenJPAConfiguration config = (OpenJPAConfiguration)getProvider().getConfiguration(); + setDataCache(config.getDataCacheManagerInstance().getSystemDataCache()); + } + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DynamicProvider.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DynamicProvider.java new file mode 100644 index 000000000..26fa8c886 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/DynamicProvider.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.lib.instrumentation.AbstractInstrumentationProvider; +import org.apache.openjpa.lib.instrumentation.Instrument; + +public class DynamicProvider extends AbstractInstrumentationProvider { + + public static final String[] DYNAMIC_INSTRUMENT_ALIASES = { }; + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + for (Instrument inst : getInstruments()) { + stopInstrument(inst); + } + } + + public void startInstrument(Instrument instrument) { + instrument.start(); + } + + public void stopInstrument(Instrument instrument, boolean force) { + instrument.stop(); + } + + @Override + public String[] getInstrumentAliases() { + return DYNAMIC_INSTRUMENT_ALIASES; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QCInstrument.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QCInstrument.java new file mode 100644 index 000000000..3311afe92 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QCInstrument.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.conf.OpenJPAConfiguration; + +public class QCInstrument extends AbstractQueryCacheInstrument { + + public static final String NAME = "SimpleQCInstrument"; + + @Override + public String getName() { + return NAME; + } + + public void initialize() { + OpenJPAConfiguration config = (OpenJPAConfiguration)getProvider().getConfiguration(); + setQueryCache(config.getDataCacheManagerInstance().getSystemQueryCache()); + } + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QSCInstrument.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QSCInstrument.java new file mode 100644 index 000000000..6594c12fc --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/QSCInstrument.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.conf.OpenJPAConfiguration; + +public class QSCInstrument extends AbstractPreparedQueryCacheInstrument { + + public static final String NAME = "SimpleQSCInstrument"; + + @Override + public String getName() { + return NAME; + } + + @Override + public void initialize() { + OpenJPAConfiguration config = (OpenJPAConfiguration)getProvider().getConfiguration(); + setPreparedQueryCache(config.getQuerySQLCacheInstance()); + } + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/SimpleProvider.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/SimpleProvider.java new file mode 100644 index 000000000..fa519ebfe --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/SimpleProvider.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import org.apache.openjpa.lib.instrumentation.AbstractInstrumentationProvider; +import org.apache.openjpa.lib.instrumentation.Instrument; + +public class SimpleProvider extends AbstractInstrumentationProvider { + + public static final String[] SIMPLE_INSTRUMENT_ALIASES = { + "DataCache", "org.apache.openjpa.instrumentation.DCInstrument", + "QueryCache","org.apache.openjpa.instrumentation.QCInstrument", + "QuerySQLCache","org.apache.openjpa.instrumentation.QSCInstrument" + }; + + public void start() { + setStarted(true); + } + + public void stop() { + setStarted(false); + for (Instrument inst : getInstruments()) { + stopInstrument(inst); + } + } + + public void startInstrument(Instrument instrument) { + instrument.start(); + } + + public void stopInstrument(Instrument instrument, boolean force) { + instrument.stop(); + } + + @Override + public String[] getInstrumentAliases() { + return SIMPLE_INSTRUMENT_ALIASES; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/TestInstrumentationProvider.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/TestInstrumentationProvider.java new file mode 100644 index 000000000..583846221 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/instrumentation/TestInstrumentationProvider.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.openjpa.instrumentation; + +import java.util.Set; + +import javax.persistence.EntityManager; + +import org.apache.openjpa.lib.instrumentation.Instrument; +import org.apache.openjpa.lib.instrumentation.InstrumentationProvider; +import org.apache.openjpa.persistence.test.SingleEMFTestCase; + +/** + * Verifies the configuration and usage of a simple instrumentation + * provider. + * @author jrbauer + * + */ +public class TestInstrumentationProvider extends SingleEMFTestCase { + + public static final String INSTRUMENTATION = + "org.apache.openjpa.instrumentation.SimpleProvider(Instrument='DataCache,QueryCache,QuerySQLCache')"; + + public void setUp() throws Exception { + super.setUp("openjpa.Instrumentation", + INSTRUMENTATION, + "openjpa.DataCache", + "true(EnableStatistics=true)", + "openjpa.QueryCache", + "true", + "openjpa.RemoteCommitProvider", + "sjvm"); + } + + /** + * Verifies simple instrumentation provider config with instruments defined + * for data cache and query cache. + */ + public void testProviderConfig() { + // Verify an EMF was created with the supplied instrumentation + assertNotNull(emf); + + // Verify the instrumentation value was stored in the config + String instrValue = emf.getConfiguration().getInstrumentation(); + assertEquals(instrValue, INSTRUMENTATION); + + // Verify an instrumentation manager is available + InstrumentationManager mgr = emf.getConfiguration().getInstrumentationManagerInstance(); + assertNotNull(mgr); + + // Verify the manager is managing the correct provider + Set providers = mgr.getProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + InstrumentationProvider provider = providers.iterator().next(); + assertEquals(provider.getClass(), SimpleProvider.class); + + // Verify the provider has instruments registered for the caches + Set instruments = provider.getInstruments(); + assertNotNull(instruments); + assertEquals(3,instruments.size()); + + // Lightweight verification of the instruments + Instrument inst = provider.getInstrumentByName(DCInstrument.NAME); + assertNotNull(inst); + assertTrue(inst instanceof DataCacheInstrument); + DataCacheInstrument dci = (DataCacheInstrument)inst; + assertEquals(dci.getCacheName(), "default"); + inst = provider.getInstrumentByName(QCInstrument.NAME); + assertNotNull(inst); + assertTrue(inst instanceof QueryCacheInstrument); + inst = provider.getInstrumentByName(QSCInstrument.NAME); + assertNotNull(inst); + assertTrue(inst instanceof PreparedQueryCacheInstrument); + } + + /** + * Verifies configuring and adding an instrument to a provider after the provider + * has been initialized within the persistence unit. + */ + public void testDynamicInstrumentConfig() { + InstrumentationManager mgr = emf.getConfiguration().getInstrumentationManagerInstance(); + assertNotNull(mgr); + + Set providers = mgr.getProviders(); + assertNotNull(providers); + assertEquals(1, providers.size()); + InstrumentationProvider provider = providers.iterator().next(); + assertEquals(provider.getClass(), SimpleProvider.class); + + verifyBrokerLevelInstrument(provider); + } + + /** + * Verifies configuring and adding an instrumentation provider dynamically after + * the persistence unit has been created. + */ + public void testDynamicProviderConfig() { + InstrumentationManager mgr = emf.getConfiguration().getInstrumentationManagerInstance(); + assertNotNull(mgr); + + DynamicProvider dyp = new DynamicProvider(); + mgr.manageProvider(dyp); + verifyBrokerLevelInstrument(dyp); + assertTrue(dyp.isStarted()); + assertNotNull(dyp.getInstrumentByName(BrokerLevelInstrument.NAME)); + assertEquals(2, mgr.getProviders().size()); + } + + public void verifyBrokerLevelInstrument(InstrumentationProvider provider) { + // Create a new broker level instrument and register it with the + // provider + BrokerLevelInstrument bli = new BrokerLevelInstrument(); + provider.addInstrument(bli); + // Verify instrument has not been initialized or started + assertFalse(bli.isInitialized()); + assertFalse(bli.isStarted()); + + // Create a new EM/Broker + EntityManager em = emf.createEntityManager(); + // Vfy the instrument has been initialized and started + assertTrue(bli.isInitialized()); + assertTrue(bli.isStarted()); + // Close the EM/Broker + em.close(); + // Vfy the instrument has stopped + assertFalse(bli.isStarted()); + } + + /** + * Verifies the cache metrics are available through simple instrumentation. + */ +// public void testCacheInstruments() { +// +// } + + /** + * Verifies multiple instrumentation providers can be specified. + */ +// public void testMultipleProviderConfig() { +// +// } +}