package org.visualvm.demoapplicationtype.application;
import com.sun.tools.visualvm.core.datasource.DataSource;
import com.sun.tools.visualvm.core.datasource.DataSourceRepository;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.datasupport.DataChangeEvent;
import com.sun.tools.visualvm.core.datasupport.DataChangeListener;
import com.sun.tools.visualvm.core.datasupport.DataRemovedListener;
import com.sun.tools.visualvm.core.explorer.ExplorerExpansionListener;
import com.sun.tools.visualvm.core.explorer.ExplorerSupport;
import com.sun.tools.visualvm.core.scheduler.Quantum;
import com.sun.tools.visualvm.core.scheduler.ScheduledTask;
import com.sun.tools.visualvm.core.scheduler.Scheduler;
import com.sun.tools.visualvm.core.scheduler.SchedulerTask;
import com.sun.tools.visualvm.tools.jmx.JmxModel;
import com.sun.tools.visualvm.tools.jmx.JmxModelFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import org.openide.util.Exceptions;
import org.visualvm.demoapplicationtype.datasource.AnagramDataSource;
import org.visualvm.demoapplicationtype.model.AnagramModel;
public class AnagramApplicationProvider implements DataChangeListener<AnagramModel>, DataRemovedListener<AnagramModel>, ExplorerExpansionListener {
private static final AnagramApplicationProvider INSTANCE = new AnagramApplicationProvider();
private final Map<AnagramModel, ScheduledTask> taskMap = new HashMap<AnagramModel, ScheduledTask>();
private static class LazyLoadingSource extends AnagramDataSource {
private String message;
private AnagramModel parent;
public LazyLoadingSource(String message, AnagramModel parent) {
this.message = message;
this.parent = parent;
}
@Override
public DataSourceDescriptor getDescriptor() {
return new DataSourceDescriptor(this) {
@Override
public int getAutoExpansionPolicy() {
return EXPAND_NEVER;
}
@Override
public String getName() {
return message;
}
};
}
}
private class DiscoveryTask implements SchedulerTask {
private AnagramModel model;
private volatile boolean running;
public DiscoveryTask(AnagramModel model) {
this.model = model;
}
public void onSchedule(long timeStamp) {
if (running) return;
running = true;
try {
JmxModel jmx = JmxModelFactory.getJmxModelFor(model.getApplication());
if (jmx == null || jmx.getConnectionState() != JmxModel.ConnectionState.CONNECTED) {
return;
}
MBeanServerConnection conn = jmx.getMBeanServerConnection();
ObjectName obj = new ObjectName("com.toy.anagrams.mbeans:type=AnagramsStats");
MBeanInfo infos = conn.getMBeanInfo(obj);
MBeanAttributeInfo[] attrs = infos.getAttributes();
Set<AnagramApplication> currentApps = new HashSet<AnagramApplication>();
for (int i = 0; i < attrs.length; i++) {
MBeanAttributeInfo attr = attrs[i];
AnagramMbeansModule attrModule = new AnagramMbeansModule(attr != null ? (attr.getName() + " (" + attr.getType() + ")") : attr.getName(), attr.getName(), model);
currentApps.add(attrModule);
}
Set<AnagramDataSource> toRemoveApps = new HashSet<AnagramDataSource>(model.getRepository().getDataSources(AnagramDataSource.class));
Set<AnagramDataSource> toAdd = new HashSet<AnagramDataSource>(currentApps);
toRemoveApps.removeAll(currentApps);
toAdd.removeAll(model.getRepository().getDataSources());
Set<LazyLoadingSource> lazy = model.getRepository().getDataSources(LazyLoadingSource.class);
Set<AnagramDataSource> toRemove = new HashSet<AnagramDataSource>(toRemoveApps);
toRemove.addAll(lazy);
if (currentApps.size() == 0) {
LazyLoadingSource unavailable = new LazyLoadingSource("Unavailable", model);
toAdd.add(unavailable);
toRemove.remove(unavailable);
}
toAdd.removeAll(lazy);
if (toAdd.size() > 0 || toRemove.size() > 0) {
model.getRepository().addDataSources(toAdd);
model.getRepository().removeDataSources(toRemove);
}
} catch (MalformedObjectNameException ex) {
Exceptions.printStackTrace(ex);
} catch (NullPointerException ex) {
Exceptions.printStackTrace(ex);
} catch (InstanceNotFoundException ex) {
Exceptions.printStackTrace(ex);
} catch (IntrospectionException ex) {
Exceptions.printStackTrace(ex);
} catch (ReflectionException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
running = false;
}
}
}
public void dataChanged(DataChangeEvent<AnagramModel> event) {
if (event.getAdded().isEmpty() && event.getRemoved().isEmpty()) {
addModels(event.getCurrent());
} else {
addModels(event.getAdded());
removeModels(event.getRemoved());
}
}
private void addModels(Set<AnagramModel> models) {
for (AnagramModel model : models) {
AnagramDataSource lazyDS = new LazyLoadingSource("Please Wait ...",model);
model.getRepository().addDataSource(lazyDS);
ScheduledTask task = Scheduler.sharedInstance().schedule(new DiscoveryTask(model), Quantum.SUSPENDED);
taskMap.put(model, task);
}
}
private void removeModels(Set<AnagramModel> models) {
for (AnagramModel model : models) {
// removing the reference to the ScheduledTask practically unschedules the task
Scheduler.sharedInstance().unschedule(taskMap.remove(model));
}
}
public void dataRemoved(AnagramModel model) {
// removing the reference to the ScheduledTask practically unschedules the task
Scheduler.sharedInstance().unschedule(taskMap.remove(model));
Set<AnagramApplication> roots = model.getRepository().getDataSources(AnagramApplication.class);
model.getRepository().removeDataSources(roots);
}
public static void initialize() {
DataSourceRepository.sharedInstance().addDataChangeListener(INSTANCE, AnagramModel.class);
ExplorerSupport.sharedInstance().addExpansionListener(INSTANCE);
}
public static void shutdown() {
DataSourceRepository.sharedInstance().removeDataChangeListener(INSTANCE);
ExplorerSupport.sharedInstance().removeExpansionListener(INSTANCE);
}
public void dataSourceCollapsed(DataSource source) {
// do nothing
}
public void dataSourceExpanded(DataSource source) {
if (source instanceof AnagramModel) {
if (taskMap.containsKey(source)) {
taskMap.get(source).setInterval(Quantum.seconds(3));
}
}
}
}