Home » Eclipse Projects » Remote Application Platform (RAP) » Invalid Thread Access exception throws when using ChartJs during multiple sessions(Invalid Thread Access exception throws when using ChartJs during multiple sessions)
Invalid Thread Access exception throws when using ChartJs during multiple sessions [message #1766876] |
Wed, 28 June 2017 13:03 |
Sudesh Bulathsinhala Messages: 193 Registered: October 2010 |
Senior Member |
|
|
Hello,
We're working on a new framework to assist "LOW CODE APP" development using eclipse platform called rubix4eclipse.
https://rubix4eclipse.wordpress.com/
The framework is supporting single-source enterprise application development out of the box (RCP and RAP) with minimum java code.
We're using org.eclipse.rap.chartjs as our RAP chart provider and org.swtchart as our RCP chart provider. We have separate targets for each RCP and RAP with respective bundles.
RAP includes chartjs bundle.
Everything works fine until we start RAP client in multi sessions.
We get following error !
Invalid thread access exception
I tried to wrap the redraw() method of Chart.java around asyncExec, but still the same issue when running multi sessions, opening the same editor with chart.
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
redraw();
}
});
any idea how to fix ?
if i remove the chart from the editor, everything works fine ! (multi sessions)
FYI > multi session throws error, only after starting record navigation from both sessions, where respective data is loaded to chart for each record. Just opening the editor with chart without record actions, in both sessions do not throw the error and i can see the chart with data immediately after loading both editors. Only when we start interacting with both editors(multi sessions) using record actions, it throws the following exception.
org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:3708)
at org.eclipse.swt.SWT.error(SWT.java:3631)
at org.eclipse.swt.SWT.error(SWT.java:3602)
at org.eclipse.swt.widgets.Widget.error(Widget.java:1018)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:956)
at org.eclipse.swt.widgets.Widget.setData(Widget.java:317)
at org.eclipse.swt.widgets.Control.setData(Control.java:2519)
at org.eclipse.rap.chartjs.Chart.drawChart(Chart.java:122)
at org.eclipse.rap.chartjs.Chart.drawBarChart(Chart.java:74)
at com.rubixobjects.widgets.charts.DatasetBarChartWidgetHelperImpl.setObserverDataValueList(DatasetBarChartWidgetHelperImpl.java:156)
at com.rubixobjects.widgets.controller.DatasetController.setChartValues(DatasetController.java:1019)
at com.rubixobjects.widgets.dataset.ClientActionExecutionProvider.processNonInteruptingActions(ClientActionExecutionProvider.java:290)
at com.rubixobjects.widgets.dataset.ClientActionExecutionProvider.executeClientActionsAsynchronously(ClientActionExecutionProvider.java:205)
at com.rubixobjects.widgets.dataset.DatasetWidget.notifyObserverDataChange(DatasetWidget.java:394)
at com.rubixobjects.widgets.controller.DatasetProvider.notifyDataChange(DatasetProvider.java:455)
at com.rubixobjects.widgets.data.DatasetTextWidget.extractEntityRecordColumns(DatasetTextWidget.java:452)
at com.rubixobjects.widgets.data.DatasetTextWidget.notifyObserverRecordsetChange(DatasetTextWidget.java:616)
at com.rubixobjects.widgets.controller.DatasetProvider.notifyRecordViewObservers(DatasetProvider.java:621)
at com.rubixobjects.widgets.dataset.RecordDatasetWidget.recordViewAction(RecordDatasetWidget.java:1802)
at com.rubixobjects.widgets.controller.DatasetProvider.notifyRecordView(DatasetProvider.java:609)
at com.rubixobjects.widgets.detailtable.DatasetDetailTable$4.doubleClick(DatasetDetailTable.java:399)
at org.eclipse.jface.viewers.StructuredViewer$1.run(StructuredViewer.java:828)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:52)
at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:177)
at org.eclipse.jface.viewers.StructuredViewer.fireDoubleClick(StructuredViewer.java:826)
at org.eclipse.jface.viewers.StructuredViewer.handleDoubleSelect(StructuredViewer.java:1139)
at org.eclipse.jface.viewers.StructuredViewer$4.widgetDefaultSelected(StructuredViewer.java:1251)
at org.eclipse.jface.util.OpenStrategy.fireDefaultSelectionEvent(OpenStrategy.java:242)
at org.eclipse.jface.util.OpenStrategy.access$0(OpenStrategy.java:239)
at org.eclipse.jface.util.OpenStrategy$1.handleEvent(OpenStrategy.java:304)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:109)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:687)
at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:594)
at org.eclipse.swt.widgets.Display.executeNextEvent(Display.java:1217)
at org.eclipse.swt.widgets.Display.runPendingMessages(Display.java:1198)
at org.eclipse.swt.widgets.Display.safeReadAndDispatch(Display.java:1181)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:1173)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2733)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2694)
at org.eclipse.ui.internal.Workbench.access$5(Workbench.java:2530)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:701)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:684)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:157)
at com.rubix.erp.core.Application.start(Application.java:19)
at org.eclipse.rap.ui.internal.application.EntryPointApplicationWrapper.createUI(EntryPointApplicationWrapper.java:38)
at org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle.createUI(RWTLifeCycle.java:177)
at org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle$UIThreadController.run(RWTLifeCycle.java:290)
at java.lang.Thread.run(Thread.java:745)
at org.eclipse.rap.rwt.internal.lifecycle.UIThread.run(UIThread.java:107)
-
Attachment: rbac2.png
(Size: 124.94KB, Downloaded 227 times) -
Attachment: rbac1.png
(Size: 121.69KB, Downloaded 223 times) -
Attachment: error.png
(Size: 202.42KB, Downloaded 261 times)
[Updated on: Wed, 28 June 2017 13:51] Report message to a moderator
|
|
| |
Re: Invalid Thread Access exception throws when using ChartJs during multiple sessions [message #1766889 is a reply to message #1766887] |
Wed, 28 June 2017 15:08 |
Sudesh Bulathsinhala Messages: 193 Registered: October 2010 |
Senior Member |
|
|
Hello Ivan,
The problem comes from the Chartjs bundle we use for rendering chart on RAP client.
Yes, I see lot of static fields in chart.java bundled inside org.eclipse.rap.chartjs.
Please find below the Chart.java >>
/*******************************************************************************
* Copyright (c) 2014 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.rap.chartjs;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.rap.chartjs.internal.ChartPaintListener;
import org.eclipse.rap.json.JsonObject;
import org.eclipse.rap.json.JsonValue;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.JavaScriptLoader;
import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
import org.eclipse.rap.rwt.scripting.ClientListener;
import org.eclipse.rap.rwt.service.ResourceManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
@SuppressWarnings("deprecation")
public class Chart extends Canvas {
private static final String CHART_OPTIONS = "chartOptions";
private static final String CHART_DATA = "chartData";
private static final String CHART_TYPE = "chartType";
private static final String CHART_MIN_JS = "Chart.js";
private static final String LINE_CHART = "Line";
private static final String PIE_CHART = "Pie";
private static final String BAR_CHART = "Bar";
private static final String RADAR_CHART = "Radar";
private static final String POLAR_AREA_CHART = "PolarArea";
private static final String DOUGHNUT_CHART = "Doughnut";
public Chart( Composite parent, int style ) {
super( parent, style );
registerJS();
requireJS();
// NOTE: RAP re-transfers all attached widget data, even if only one of them changes,
// but JsonObject/JsonArray aren't deep-compared
WidgetUtil.registerDataKeys( CHART_TYPE, CHART_DATA, CHART_OPTIONS );
addPaintListener();
applyFixes();
}
public void drawLineChart( ChartRowData data ) {
drawLineChart( data, null );
}
public void drawLineChart( ChartRowData data, ChartOptions options ) {
drawChart( LINE_CHART, getLineChartOptions( options ), data.toJson() );
}
public void drawBarChart( ChartRowData data ) {
drawBarChart( data, null );
}
public void drawBarChart( ChartRowData data, ChartOptions options ) {
drawChart( BAR_CHART, getBarChartOptions( options ), data.toJson() );
}
public void drawRadarChart( ChartRowData data ) {
drawRadarChart( data, null );
}
public void drawRadarChart( ChartRowData data, ChartOptions options ) {
drawChart( RADAR_CHART, getLineChartOptions( options ), data.toJson() );
}
public void drawPolarAreaChart( ChartPointData data ) {
drawPolarAreaChart( data, null );
}
public void drawPolarAreaChart( ChartPointData data, ChartOptions options ) {
drawChart( POLAR_AREA_CHART, getSegmentChartOptions( options ), data.toJson() );
}
public void drawPieChart( ChartPointData data ) {
drawPieChart( data, null );
}
public void drawPieChart( ChartPointData data, ChartOptions options ) {
drawChart( PIE_CHART, getSegmentChartOptions( options ), data.toJson() );
}
public void drawDoughnutChart( ChartPointData data ) {
drawDoughnutChart( data, null );
}
public void drawDoughnutChart( ChartPointData data, ChartOptions options ) {
drawChart( DOUGHNUT_CHART, getSegmentChartOptions( options ), data.toJson() );
}
public void clear() {
setData( CHART_TYPE, JsonObject.NULL ); // "null" won't be synchronized
redraw();
}
private void drawChart( String type, JsonObject options, JsonValue data ) {
setData( CHART_TYPE, type );
setData( CHART_OPTIONS, options );
setData( CHART_DATA, data );
redraw();
}
private JsonObject getSegmentChartOptions( ChartOptions options ) {
if( options == null ) {
return new JsonObject();
}
JsonObject json = options.toJson();
json.set( "segmentShowStroke", json.get( "showStroke" ).asBoolean() );
json.set( "segmentStrokeWidth", json.get( "strokeWidth" ).asInt() );
return json;
}
private JsonObject getBarChartOptions( ChartOptions options ) {
if( options == null ) {
return new JsonObject();
}
JsonObject json = options.toJson();
json.set( "barShowStroke", json.get( "showStroke" ).asBoolean() );
json.set( "barStrokeWidth", json.get( "strokeWidth" ).asInt() );
return json;
}
private JsonObject getLineChartOptions( ChartOptions options ) {
if( options == null ) {
return new JsonObject();
}
JsonObject json = options.toJson();
json.set( "datasetStroke", json.get( "showStroke" ).asBoolean() );
json.set( "datasetStrokeWidth", json.get( "strokeWidth" ).asInt() );
return json;
}
private void addPaintListener() {
addListener( SWT.Paint, ChartPaintListener.getInstance() );
}
private void applyFixes() {
// See RAP Bug 391414
ClientListener listener = new ClientListener(
"function handleEvent( event ) {\n"
+ " event.widget.redraw();"
+ "}\n"
);
addListener( SWT.Show, listener );
}
private void requireJS() {
JavaScriptLoader service = RWT.getClient().getService( JavaScriptLoader.class );
service.require( RWT.getResourceManager().getLocation( CHART_MIN_JS ) );
}
private void registerJS() {
ResourceManager manager = RWT.getResourceManager();
if( !manager.isRegistered( CHART_MIN_JS ) ) {
InputStream inputStream = ChartPaintListener.class.getResourceAsStream( CHART_MIN_JS );
manager.register( CHART_MIN_JS, inputStream );
try {
inputStream.close();
} catch( IOException e ) {
throw new RuntimeException( e );
}
}
}
}
|
|
| | | |
Re: Invalid Thread Access exception throws when using ChartJs during multiple sessions [message #1766903 is a reply to message #1766895] |
Wed, 28 June 2017 16:12 |
Sudesh Bulathsinhala Messages: 193 Registered: October 2010 |
Senior Member |
|
|
Hello Ivan,
We're using RAP 3.1, it's time to migrate to 3.2 and check how much it has in store to offer this framework :)
Sure we will invest more time on suggested chart from incubator (http://git.eclipse.org/c/rap/incubator/org.eclipse.rap.incubator.chart.git)
Coming back to the context, I think i will explain the architecture abit.
We have 2 type of bundles target for both RCP and RAP.
COMMON BUNDLES
com.eclipsesource.widgets.gmaps
com.rubixobjects.emf.model
com.rubixobjects.entity
com.rubixobjects.utils
com.rubixobjects.validator
com.rubixobjects.widgets
log4j.properties
org.apache.log4j
RCP BUNDLES
com.rubixobjects.designer
com.rubixobjects.explorer
com.rubixobjects.jobs
com.rubixobjects.model
com.rubixobjects.res
com.rubixobjects.widgets.rcp
RAP BUNDLES
com.rubixobjects.widgets.rap
org.eclipse.rap.chartjs
RAP bundles compared to RCP is minimum, as RAP only requires minimal set of bundles for runtime rendering. However RCP requires additional bundles for application life cycle management, which includes importing entities and designing editors using drag'n drop, etc.
Most SWT widgets works for both RCP and RAP, like Text, Combo, Date, etc. However when we don't have such luxury, for example in the case of Charts, we use 2 different providers. For RCP we use swtchartand RAP we use chartjs. The architecture does not impose RCP or RAP boundaries for end user. End user will be creating meta models. These models get dynamically loaded by composite assembly factories and creates respective RCP, RAP editor UI counterparts. For that we're using 2 fragment projects.
FRAGMENT BUNDLES
com.rubixobjects.widgets.rcp
com.rubixobjects.widgets.rap
When chart model instance is found during rendering by component assembly factory, it uses following to delegate the call to respective fragments (RCP or RAP).
At runtime, this approach delegates the call to RCP or RAP, enabling the framework to pick the component dynamically. Both com.rubixobjects.widgets.rcp and com.rubixobjects.widgets.rap bundles provide their respective chart implementations.
package com.rubixobjects.widgets.charts;
import java.util.List;
import org.eclipse.swt.widgets.Composite;
import com.rubixobjects.entity.core.EntityObject;
import com.rubixobjects.widgets.ImplementationLoader;
import com.rubixobjects.widgets.controller.IDatasetBroadcast;
import com.rubixobjects.widgets.sys.BaseDatasetWidget;
public abstract class DatasetBarChartWidgetHelper extends BaseDatasetWidget {
private static final DatasetBarChartWidgetHelper IMPL;
static {
IMPL = (DatasetBarChartWidgetHelper) ImplementationLoader.newInstance(DatasetBarChartWidgetHelper.class);
}
public static Object createWidget(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
return IMPL.create(name, caption, datasetBroadcast, composite, entity, chartConfigurations);
}
protected abstract Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations);
}
Herewith I'm attaching DatasetBarChartWidgetHelperImpl, which is the implementation provider for RAP in com.rubixobjects.widgets.rap bundle.
package com.rubixobjects.widgets.charts;
import java.util.List;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.rap.chartjs.Chart;
import org.eclipse.rap.chartjs.ChartOptions;
import org.eclipse.rap.chartjs.ChartRowData;
import org.eclipse.rap.chartjs.ChartStyle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import com.rubixobjects.entity.column.type.ChartItemColumn;
import com.rubixobjects.entity.column.type.EntityColumn;
import com.rubixobjects.entity.column.type.IChartEntityColumn;
import com.rubixobjects.entity.core.EntityObject;
import com.rubixobjects.entity.core.RecordActionType;
import com.rubixobjects.widgets.controller.IDatasetBroadcast;
import com.rubixobjects.widgets.controller.IDatasetChartObserver;
import com.rubixobjects.widgets.controller.IDatasetObserver;
public class DatasetBarChartWidgetHelperImpl extends DatasetBarChartWidgetHelper
implements IDatasetObserver, IDatasetChartObserver {
private Chart chart;
@Override
protected Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
setDatasetBroadcast(datasetBroadcast);
datasetBroadcast.addObserver(this);
this.name = name;
// chart-composite
final Composite chartComposite = new Composite(composite, SWT.NONE);
chartComposite.setBackgroundMode(SWT.INHERIT_DEFAULT);
chartComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
final FormLayout layout = new FormLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.marginLeft = 0;
layout.marginRight = 0;
layout.marginTop = 0;
layout.marginBottom = 0;
chartComposite.setLayout(layout);
final FormData data = new FormData();
data.left = new FormAttachment(0);
data.right = new FormAttachment(100);
data.top = new FormAttachment(0);
data.bottom = new FormAttachment(100);
chartComposite.setLayoutData(data);
// header
final CLabel header = new CLabel(chartComposite, SWT.NONE);
header.setText(caption);
header.setForeground(new Color(chartComposite.getDisplay(), 112, 146, 190));
header.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
FormData formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(0, 7);
header.setLayoutData(formData);
// separator
final Label seperator = new Label(chartComposite, SWT.SEPARATOR | SWT.SHADOW_OUT | SWT.HORIZONTAL);
formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(header);
seperator.setLayoutData(formData);
// chart
chart = new Chart(chartComposite, SWT.NONE);
formData = new FormData();
formData.left = new FormAttachment(0);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(seperator);
formData.bottom = new FormAttachment(100);
chart.setLayoutData(formData);
final EntityColumn column = entity.getChartByName(name);
final String[] namesarray = new String[((IChartEntityColumn) column).getItems().size()];
final int[] valuesarray = new int[((IChartEntityColumn) column).getItems().size()];
for (int index = 0; index < ((IChartEntityColumn) column).getItems().size(); index++) {
namesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getName();
valuesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getValue().intValue();
}
final ChartOptions options = new ChartOptions();
options.setAnimation(true);
options.setShowToolTips(true);
options.setScaleBeginAtZero(true);
options.setBezierCurve(true);
options.setShowFill(true);
options.setScaleShowLabels(true);
options.setPointDotRadius(3);
options.setStrokeWidth(1);
final ChartStyle chartStyle = new ChartStyle(151, 187, 205, 0.7f);
chartStyle.setPointColor(new RGB(100, 220, 100));
final ChartRowData chartrowdata = new ChartRowData(namesarray).addRow(valuesarray, chartStyle);
chart.drawBarChart(chartrowdata, options);
return this;
}
@Override
public String getName() {
return name;
}
/* -------------------------------------- */
/* OBSERVER IMPLEMENTATION */
/* -------------------------------------- */
@Override
public String getObserverName() {
return name;
}
@Override
public void setObserverDataValueList(final List<ChartItemColumn> chartItems) {
final String[] namesarray = new String[chartItems.size()];
final int[] valuesarray = new int[chartItems.size()];
for (int index = 0; index < chartItems.size(); index++) {
namesarray[index] = chartItems.get(index).getName();
valuesarray[index] = chartItems.get(index).getValue().intValue();
}
final ChartOptions options = new ChartOptions();
options.setAnimation(true);
options.setShowToolTips(true);
options.setScaleBeginAtZero(true);
options.setBezierCurve(true);
options.setShowFill(true);
options.setScaleShowLabels(true);
options.setPointDotRadius(1);
options.setStrokeWidth(1);
final ChartStyle chartStyle = new ChartStyle(151, 187, 205, 0.7f);
chartStyle.setPointColor(new RGB(100, 220, 100));
final ChartRowData chartrowdata = new ChartRowData(namesarray).addRow(valuesarray, chartStyle);
if (chart != null && chart.isDisposed() == false) {
chart.drawBarChart(chartrowdata, options);
}
}
@Override
public void clearObserver() {
// TODO Auto-generated method stub
}
@Override
public void setObserverEnable() {
// TODO Auto-generated method stub
}
@Override
public void setObserverDisable() {
// TODO Auto-generated method stub
}
@Override
public void notifyObserverActionEvent(final String identifier, final RecordActionType recordActionType,
final boolean isRequired) {
// TODO Auto-generated method stub
}
}
|
|
| |
Re: Invalid Thread Access exception throws when using ChartJs during multiple sessions [message #1766928 is a reply to message #1766913] |
Wed, 28 June 2017 18:29 |
Sudesh Bulathsinhala Messages: 193 Registered: October 2010 |
Senior Member |
|
|
Hello Ivan,
In my DatasetBarChartWidgetHelperImpl chart implementation provider, i'm calling the drawBarChart like this.
Now the behavior is somewhat different, the latest session gets the upper hand and the previous ones don't draw chart data during record navigation.
However the application is not throwing Invalid thread exception any more and the other parts remain to load the data during navigation.
Change >>
if (chart != null && chart.isDisposed() == false) {
chart.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
chart.drawBarChart(chartrowdata, options);
}
});
}
DatasetBarChartWidgetHelperImpl
package com.rubixobjects.widgets.charts;
import java.util.List;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.rap.chartjs.Chart;
import org.eclipse.rap.chartjs.ChartOptions;
import org.eclipse.rap.chartjs.ChartRowData;
import org.eclipse.rap.chartjs.ChartStyle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import com.rubixobjects.entity.column.type.ChartItemColumn;
import com.rubixobjects.entity.column.type.EntityColumn;
import com.rubixobjects.entity.column.type.IChartEntityColumn;
import com.rubixobjects.entity.core.EntityObject;
import com.rubixobjects.entity.core.RecordActionType;
import com.rubixobjects.widgets.controller.IDatasetBroadcast;
import com.rubixobjects.widgets.controller.IDatasetChartObserver;
import com.rubixobjects.widgets.controller.IDatasetObserver;
public class DatasetBarChartWidgetHelperImpl extends DatasetBarChartWidgetHelper
implements IDatasetObserver, IDatasetChartObserver {
private Chart chart;
@Override
protected Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
setDatasetBroadcast(datasetBroadcast);
datasetBroadcast.addObserver(this);
this.name = name;
// chart-composite
final Composite chartComposite = new Composite(composite, SWT.NONE);
chartComposite.setBackgroundMode(SWT.INHERIT_DEFAULT);
chartComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
final FormLayout layout = new FormLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.marginLeft = 0;
layout.marginRight = 0;
layout.marginTop = 0;
layout.marginBottom = 0;
chartComposite.setLayout(layout);
final FormData data = new FormData();
data.left = new FormAttachment(0);
data.right = new FormAttachment(100);
data.top = new FormAttachment(0);
data.bottom = new FormAttachment(100);
chartComposite.setLayoutData(data);
// header
final CLabel header = new CLabel(chartComposite, SWT.NONE);
header.setText(caption);
header.setForeground(new Color(chartComposite.getDisplay(), 112, 146, 190));
header.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
FormData formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(0, 7);
header.setLayoutData(formData);
// separator
final Label seperator = new Label(chartComposite, SWT.SEPARATOR | SWT.SHADOW_OUT | SWT.HORIZONTAL);
formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(header);
seperator.setLayoutData(formData);
// chart
chart = new Chart(chartComposite, SWT.NONE);
formData = new FormData();
formData.left = new FormAttachment(0);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(seperator);
formData.bottom = new FormAttachment(100);
chart.setLayoutData(formData);
final EntityColumn column = entity.getChartByName(name);
final String[] namesarray = new String[((IChartEntityColumn) column).getItems().size()];
final int[] valuesarray = new int[((IChartEntityColumn) column).getItems().size()];
for (int index = 0; index < ((IChartEntityColumn) column).getItems().size(); index++) {
namesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getName();
valuesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getValue().intValue();
}
final ChartOptions options = new ChartOptions();
options.setAnimation(true);
options.setShowToolTips(true);
options.setScaleBeginAtZero(true);
options.setBezierCurve(true);
options.setShowFill(true);
options.setScaleShowLabels(true);
options.setPointDotRadius(3);
options.setStrokeWidth(1);
final ChartStyle chartStyle = new ChartStyle(151, 187, 205, 0.7f);
chartStyle.setPointColor(new RGB(100, 220, 100));
final ChartRowData chartrowdata = new ChartRowData(namesarray).addRow(valuesarray, chartStyle);
if (chart != null && chart.isDisposed() == false) {
chart.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
chart.drawBarChart(chartrowdata, options);
}
});
}
return this;
}
@Override
public String getName() {
return name;
}
/* -------------------------------------- */
/* OBSERVER IMPLEMENTATION */
/* -------------------------------------- */
@Override
public String getObserverName() {
return name;
}
@Override
public void setObserverDataValueList(final List<ChartItemColumn> chartItems) {
final String[] namesarray = new String[chartItems.size()];
final int[] valuesarray = new int[chartItems.size()];
for (int index = 0; index < chartItems.size(); index++) {
namesarray[index] = chartItems.get(index).getName();
valuesarray[index] = chartItems.get(index).getValue().intValue();
}
final ChartOptions options = new ChartOptions();
options.setAnimation(true);
options.setShowToolTips(true);
options.setScaleBeginAtZero(true);
options.setBezierCurve(true);
options.setShowFill(true);
options.setScaleShowLabels(true);
options.setPointDotRadius(1);
options.setStrokeWidth(1);
final ChartStyle chartStyle = new ChartStyle(151, 187, 205, 0.7f);
chartStyle.setPointColor(new RGB(100, 220, 100));
final ChartRowData chartrowdata = new ChartRowData(namesarray).addRow(valuesarray, chartStyle);
if (chart != null && chart.isDisposed() == false) {
chart.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
chart.drawBarChart(chartrowdata, options);
}
});
}
}
@Override
public void clearObserver() {
// TODO Auto-generated method stub
}
@Override
public void setObserverEnable() {
// TODO Auto-generated method stub
}
@Override
public void setObserverDisable() {
// TODO Auto-generated method stub
}
@Override
public void notifyObserverActionEvent(final String identifier, final RecordActionType recordActionType,
final boolean isRequired) {
// TODO Auto-generated method stub
}
}
|
|
| |
Re: Invalid Thread Access exception throws when using ChartJs during multiple sessions [message #1767206 is a reply to message #1766964] |
Mon, 03 July 2017 14:39 |
Sudesh Bulathsinhala Messages: 193 Registered: October 2010 |
Senior Member |
|
|
Hello Ivan,
Found the solution !!!
If we look at single sourcing implementation provider below, we call the create method. This method always return same object instance which internally creates a new chart every time. So basically the same object(DatasetBarChartWidgetHelperImpl) is shared with multiple charts widgets across sessions. We made changes to return new object(DatasetBarChartWidgetHelperImpl) having a new chart for each instance, and it worked !
public abstract class DatasetBarChartWidgetHelper extends BaseDatasetWidget {
private static final DatasetBarChartWidgetHelper IMPL;
static {
IMPL = (DatasetBarChartWidgetHelper) ImplementationLoader.newInstance(DatasetBarChartWidgetHelper.class);
}
public static Object createWidget(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
return IMPL.create(name, caption, datasetBroadcast, composite, entity, chartConfigurations);
}
protected abstract Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations);
}
OLD this basically returns the same object with new chart for every call, so the object itself is shared
public class DatasetBarChartWidgetHelperImpl extends DatasetBarChartWidgetHelper
implements IDatasetObserver, IDatasetChartObserver {
private Chart chart;
@Override
protected Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
setDatasetBroadcast(datasetBroadcast);
datasetBroadcast.addObserver(this);
this.name = name;
// chart-composite
final Composite chartComposite = new Composite(composite, SWT.NONE);
chartComposite.setBackgroundMode(SWT.INHERIT_DEFAULT);
chartComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
final FormLayout layout = new FormLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.marginLeft = 0;
layout.marginRight = 0;
layout.marginTop = 0;
layout.marginBottom = 0;
chartComposite.setLayout(layout);
final FormData data = new FormData();
data.left = new FormAttachment(0);
data.right = new FormAttachment(100);
data.top = new FormAttachment(0);
data.bottom = new FormAttachment(100);
chartComposite.setLayoutData(data);
// header
final CLabel header = new CLabel(chartComposite, SWT.NONE);
header.setText(caption);
header.setForeground(new Color(chartComposite.getDisplay(), 112, 146, 190));
header.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
FormData formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(0, 7);
header.setLayoutData(formData);
// separator
final Label seperator = new Label(chartComposite, SWT.SEPARATOR | SWT.SHADOW_OUT | SWT.HORIZONTAL);
formData = new FormData();
formData.left = new FormAttachment(0, 7);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(header);
seperator.setLayoutData(formData);
// chart
chart = new Chart(chartComposite, SWT.NONE);
formData = new FormData();
formData.left = new FormAttachment(0);
formData.right = new FormAttachment(100);
formData.top = new FormAttachment(seperator);
formData.bottom = new FormAttachment(100);
chart.setLayoutData(formData);
final EntityColumn column = entity.getChartByName(name);
final String[] namesarray = new String[((IChartEntityColumn) column).getItems().size()];
final int[] valuesarray = new int[((IChartEntityColumn) column).getItems().size()];
for (int index = 0; index < ((IChartEntityColumn) column).getItems().size(); index++) {
namesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getName();
valuesarray[index] = ((IChartEntityColumn) column).getItems().get(index).getValue().intValue();
}
final ChartOptions options = new ChartOptions();
options.setAnimation(true);
options.setShowToolTips(true);
options.setScaleBeginAtZero(true);
options.setBezierCurve(true);
options.setShowFill(true);
options.setScaleShowLabels(true);
options.setPointDotRadius(3);
options.setStrokeWidth(1);
final ChartStyle chartStyle = new ChartStyle(151, 187, 205, 0.7f);
chartStyle.setPointColor(new RGB(100, 220, 100));
final ChartRowData chartrowdata = new ChartRowData(namesarray).addRow(valuesarray, chartStyle);
chart.drawBarChart(chartrowdata, options);
return this;
}
}
NEW this basically returns the new object with new chart for every call, so the object itself is not shared
public class DatasetBarChartWidgetHelperImpl extends DatasetBarChartWidgetHelper {
@Override
protected Object create(final String name, final String caption, final IDatasetBroadcast datasetBroadcast,
final Composite composite, final EntityObject entity, final List<ChartConfiguration> chartConfigurations) {
return new DatasetBarChartWidget(name, caption, datasetBroadcast, composite, entity, chartConfigurations);
}
}
By delegating the DatasetBarChartWidgetHelperImpl to return new instance(DatasetBarChartWidget) for each create method call, now we can keep multiple sessions in perfect harmony.
Thanks Ivan for your valuable suggestions.
Will be starting to integrate Apache Shiro with Rubix framework to implement permission and access control. Will keep you posted further developments.
Regards,
Sudesh
[Updated on: Mon, 03 July 2017 14:43] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Thu Jan 16 06:48:51 GMT 2025
Powered by FUDForum. Page generated in 0.04508 seconds
|