/*******************************************************************************
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package javax.tools.diagnostics.vm;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import javax.tools.diagnostics.vm.spi.delegates.HProfMBeanDumpDelegate;
import javax.tools.diagnostics.vm.spi.delegates.HProfSignalTriggeredDumpDelegate;
import javax.tools.diagnostics.vm.spi.delegates.IBMSPIBasedHeapDumpDelegate;
import javax.tools.diagnostics.vm.spi.delegates.IBMSPIBasedSystemDumpDelegate;
import javax.tools.diagnostics.vm.spi.delegates.JavaDumpDelegate;
/**
* <p>
* Standard mechanism that allows a java application to trigger a dump for the
* executing JVM.
*
* @experimental This is an experimental addition to the API and is subject to
* change
*
*/
public class DumpFactory {
// store for the mapping between a dump descriptor and its owning delegate
private Map<String,DumpInitiatorDelegate> availableInitiators=new TreeMap<String,DumpInitiatorDelegate>();
// default factory - populated when getDefault is first called
private static DumpFactory defaultDumpFactory=null;
private DumpInitiatorDelegate defaultInitiatorDelegate=null;
/**
* Get the default dump initiator
*
* @return
*/
public DumpInitiatorDelegate getDefaultInitiatorDelegate() {
return defaultInitiatorDelegate;
}
/**
* sets the default dump initiator.
* @param defaultInitiatorDelegate
*/
public void setDefaultInitiatorDelegate(
DumpInitiatorDelegate defaultInitiatorDelegate) {
this.defaultInitiatorDelegate = defaultInitiatorDelegate;
}
/**
* Instantiate a dump factory that can be used to trigger dumps
*/
public DumpFactory() {
}
/**
* Fastpath method allowing the user to trigger a dump using the default
* dump method
* @throws IOException
*/
public void dump() throws IOException {
getDefaultInitiatorDelegate().createDumpHandle().dump();
}
/**
* Fastpath method allowing the user to trigger a standard dump for the given
* data format
* @throws IOException
*/
public void dump(String id) throws IOException {
getInitiator(id).createDumpHandle().dump();
}
/**
* Fastpath method to create a dump from a dump type that can support the data
* requested.
*
* @return a valid dump handle
*/
public void dump(DumpDescriptor desc)throws IOException{
// FIXME ! have to work on how this all gets resolved
}
/**
* Get the default Dump factory.
* Returns a Dump factory populated with all available dump initiators
*
* @return default dump factory
*/
public static DumpFactory getDefault() {
if(defaultDumpFactory==null) {
DumpFactory d=new DumpFactory();
d.loadStandardInitiators();
defaultDumpFactory=d;
}
return defaultDumpFactory;
}
/**
* Looks for commonly available dump initiators and add them to
* this instances configuration
*/
public void loadStandardInitiators() {
DumpInitiatorDelegate sigdump=instantiateOverrideDelegate();
if(sigdump!=null && sigdump.available()) addInitiator(sigdump);
// sun hprof dump
sigdump=new HProfSignalTriggeredDumpDelegate();
if(sigdump.available()) addInitiator(sigdump);
// IBM SPI dumps
sigdump=new IBMSPIBasedSystemDumpDelegate();
if(sigdump.available()) {
addInitiator(sigdump);
// try for the other IBM dumps
sigdump=new IBMSPIBasedHeapDumpDelegate();
if(sigdump.available()) addInitiator(sigdump);
}
// Sun Hotspot HProf MBean
DumpInitiatorDelegate mbeanDump = new HProfMBeanDumpDelegate();
if (mbeanDump.available()) {
addInitiator(mbeanDump);
}
addInitiator(new JavaDumpDelegate());
}
/**
* Add a dump initiator to the available choices for this dump factory.
* If the default dump initiator is null then the dump initiator specified
* on this call will become the default initiator
*/
private void addInitiator(DumpInitiatorDelegate sigdump) {
String dumpname=sigdump.getDumpType();
availableInitiators.put(dumpname,sigdump);
if(defaultInitiatorDelegate==null) defaultInitiatorDelegate=sigdump;
}
private static final String overridingPropertyName = "javax.tools.diagnositics.vm.dumpinitiator";
/**
* Returns a Dump handle for the default dump type used by this JVM
*
* @return a valid dump handle
*/
public DumpHandle createDumpHandle() {
return defaultInitiatorDelegate.createDumpHandle();
}
/**
* Returns a Dump handle for a dump type that can support the data
* requested.
*
* @return a valid dump handle
*/
public DumpHandle createDumpHandle(DumpDescriptor desc) {
return null; // FIXME ! have to work on how this all gets resolved
}
/**
* Returns an initiator that can produce a dump of the required format.
* If no initiator exists which can handle the format then null is returned
*
* @param format
* @return supporting initiator or null
*/
public DumpInitiatorDelegate getInitiator(String format) {
return availableInitiators.get(format);
}
/**
* Returns the set of available Initiators.
*
* Always returns a set.
*
* @return
*/
public Collection<DumpInitiatorDelegate> getAvailableInitiators() {
return Collections.unmodifiableCollection(availableInitiators.values());
}
/**
* Instantiates a Dump delegate class to handle dump requests based on
* the presence of the override system property {@link initiatorPropertyName}
*
* It will be used in preference to any other auto discovered delegates.
*
* If the override does not exist or cannot be instantiated then null is returned
*
* @return override delegate instance
*/
public DumpInitiatorDelegate instantiateOverrideDelegate() {
DumpInitiatorDelegate delegate = null;
// look for an override to the dump delegate
String delegateName = System.getProperty(overridingPropertyName);
if (delegateName != null) {
delegate = loadDelegateClass(delegateName);
if (delegate != null)
return delegate;
}
return null;
}
private DumpInitiatorDelegate loadDelegateClass(String delegateName) {
try {
Class clazz = Class.forName(delegateName);
return (DumpInitiatorDelegate) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}