Skip to content

Commit

Permalink
NMS-8589: Cleanup NodeMapsApplication to destroy scheduled refresh to…
Browse files Browse the repository at this point in the history
… avoid Thread and Out of Memory Leak as well as Performance issues.
  • Loading branch information
Markus von Rüden committed Jul 19, 2016
1 parent 195ef47 commit 5a97277
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 68 deletions.
Expand Up @@ -33,10 +33,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.opennms.core.criteria.CriteriaBuilder;
import org.opennms.core.criteria.restrictions.Restrictions;
Expand All @@ -61,39 +57,22 @@
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionOperations;

import com.github.wolfie.refresher.Refresher;

/**
* @author Marcus Hellberg (marcus@vaadin.com)
*/
public class MapWidgetComponent extends NodeMapComponent implements GeoAssetProvider {

private class DynamicUpdateRefresher implements Refresher.RefreshListener{
private static final long serialVersionUID = 801233170298353060L;

@Override
public void refresh(Refresher refresher) {
refreshView();
}
}

private static final long serialVersionUID = -6364929103619363239L;
private static final Logger LOG = LoggerFactory.getLogger(MapWidgetComponent.class);

private final ScheduledExecutorService m_executor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
@Override public Thread newThread(final Runnable runnable) {
return new Thread(runnable, "NodeMapUpdater-Thread");
}
});

private NodeDao m_nodeDao;
private AssetRecordDao m_assetDao;
private AlarmDao m_alarmDao;
private GeocoderService m_geocoderService;
private TransactionOperations m_transaction;
private Boolean m_aclsEnabled = false;

private Map<Integer,NodeEntry> m_activeNodes = new HashMap<Integer,NodeEntry>();
private Map<Integer,NodeEntry> m_activeNodes = new HashMap<>();

public NodeDao getNodeDao() {
return m_nodeDao;
Expand Down Expand Up @@ -131,30 +110,8 @@ public void setTransactionOperations(final TransactionOperations tx) {
m_transaction = tx;
}

public void init() {
m_executor.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
refreshNodeData();
}
}, 0, 5, TimeUnit.MINUTES);
checkAclsEnabled();
setupAutoRefresher();
}

private void checkAclsEnabled() {
String aclsPropValue = System.getProperty("org.opennms.web.aclsEnabled");
m_aclsEnabled = aclsPropValue != null && aclsPropValue.equals("true");
}

public void setupAutoRefresher(){
Refresher refresher = new Refresher();
refresher.setRefreshInterval(5000); //Pull every two seconds for view updates
refresher.addListener(new DynamicUpdateRefresher());
addExtension(refresher);
}

public void refresh() {
refreshView();
public MapWidgetComponent() {
m_aclsEnabled = Boolean.valueOf(System.getProperty("org.opennms.web.aclsEnabled", "false"));
}

@Override
Expand All @@ -166,7 +123,7 @@ public Collection<VertexRef> getNodesWithCoordinates() {
return nodes;
}

private void refreshView() {
public void refresh() {
if(m_aclsEnabled) {
Map<Integer, String> nodes = getNodeDao().getAllLabelsById();

Expand All @@ -180,7 +137,7 @@ private void refreshView() {
}
}

private void refreshNodeData() {
public void refreshNodeData() {
if (getNodeDao() == null) {
LOG.warn("No node DAO! Can't refresh node data.");
return;
Expand Down
Expand Up @@ -36,6 +36,10 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.opennms.features.topology.api.HasExtraComponents;
import org.opennms.features.topology.api.VerticesUpdateManager;
Expand All @@ -58,6 +62,8 @@
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.server.Page;
import com.vaadin.server.SessionDestroyEvent;
import com.vaadin.server.SessionDestroyListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Alignment;
Expand Down Expand Up @@ -124,8 +130,7 @@
})
public class NodeMapsApplication extends UI {
private static final Logger LOG = LoggerFactory.getLogger(NodeMapsApplication.class);
// private static final int REFRESH_INTERVAL = 5 * 60 * 1000;
private static final int REFRESH_INTERVAL = 10 * 1000;
private static final int REFRESH_INTERVAL = 5 * 1000;
private VerticalLayout m_rootLayout;
private VerticalLayout m_layout;

Expand All @@ -136,6 +141,12 @@ public class NodeMapsApplication extends UI {
private AlarmTable m_alarmTable;
private NodeTable m_nodeTable;

private final ScheduledExecutorService m_executor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
@Override public Thread newThread(final Runnable runnable) {
return new Thread(runnable, "NodeMapUpdater-Thread");
}
});

public void setHeaderProvider(final OnmsHeaderProvider headerProvider) {
m_headerProvider = headerProvider;
}
Expand All @@ -157,23 +168,15 @@ public void setNodeTable(final NodeTable table) {
}

private void updateWidgetView() {
if (m_layout != null) {
synchronized (m_layout) {
m_layout.removeAllComponents();

final VerticalSplitPanel bottomLayoutBar = new VerticalSplitPanel();
bottomLayoutBar.setFirstComponent(m_mapWidgetComponent);

// Split the screen 70% top, 30% bottom
bottomLayoutBar.setSplitPosition(70, Unit.PERCENTAGE);
bottomLayoutBar.setSizeFull();
bottomLayoutBar.setSecondComponent(getTabSheet());
m_layout.addComponent(bottomLayoutBar);
m_layout.markAsDirty();
}
} else {
LOG.warn("updateWidgetView() called, but there's no layout yet!");
}
final VerticalSplitPanel bottomLayoutBar = new VerticalSplitPanel();
bottomLayoutBar.setFirstComponent(m_mapWidgetComponent);

// Split the screen 70% top, 30% bottom
bottomLayoutBar.setSplitPosition(70, Unit.PERCENTAGE);
bottomLayoutBar.setSizeFull();
bottomLayoutBar.setSecondComponent(getTabSheet());
m_layout.addComponent(bottomLayoutBar);
m_layout.markAsDirty();
}

/**
Expand Down Expand Up @@ -294,6 +297,17 @@ protected void init(final VaadinRequest vaadinRequest) {
if (!NodeMapConfiguration.isValid()) {
new InvalidConfigurationWindow().open();
}
// Schedule refresh of node data
m_executor.scheduleWithFixedDelay(() -> m_mapWidgetComponent.refreshNodeData(), 0, 5, TimeUnit.MINUTES);

// If we do not shutdown the executor, the scheduler keeps refreshing the node data, even if the
// UI may already been detached, resulting at one point in a OutOfMemory. See NMS-8589.
vaadinRequest.getService().addSessionDestroyListener(new SessionDestroyListener() {
@Override
public void sessionDestroy(SessionDestroyEvent event) {
m_executor.shutdown();
}
});
}

private void createMapPanel(final String searchString, final int maxClusterRadius) {
Expand Down Expand Up @@ -358,6 +372,7 @@ private void closeQuietly(InputStream is) {
private void addRefresher() {
final Refresher refresher = new Refresher();
refresher.setRefreshInterval(REFRESH_INTERVAL);
refresher.addListener((theRefresher) -> m_mapWidgetComponent.refresh());
addExtension(refresher);
}

Expand Down
Expand Up @@ -164,7 +164,7 @@
</cm:default-properties>
</cm:property-placeholder>

<bean id="mapWidget" class="org.opennms.features.vaadin.nodemaps.internal.MapWidgetComponent" scope="prototype" init-method="init">
<bean id="mapWidget" class="org.opennms.features.vaadin.nodemaps.internal.MapWidgetComponent" scope="prototype">
<property name="nodeDao" ref="nodeDao" />
<property name="assetRecordDao" ref="assetDao" />
<property name="alarmDao" ref="alarmDao" />
Expand Down

0 comments on commit 5a97277

Please sign in to comment.