Custom Event in GWT widget is not working - java

I am working on application in Vaadin for my classes.
I have to draw some map on the screen so I'm using gwt-graphics lib.
I have also some servlet which is waiting for requests.
When some specific request will come view of the map should be changed.
It lead me to prepare custom event:
// class NewModulePositionHandler
package com.example.locator;
import com.google.gwt.event.shared.EventHandler;
public interface NewModulePositionHandler extends EventHandler {
void onNewModulePosition(NewModulePositionEvent event);
}
Below implementation of my custom event:
import com.google.gwt.event.shared.GwtEvent;
public class NewModulePositionEvent extends GwtEvent<NewModulePositionHandler> {
private static final Type<NewModulePositionHandler> TYPE = new Type<NewModulePositionHandler>();
private final String m_Color;
public NewModulePositionEvent(String color) {
m_Color = color;
}
public static Type<NewModulePositionHandler> getType() {
return TYPE;
}
public String getColor() {
return m_Color;
}
#Override
public com.google.gwt.event.shared.GwtEvent.Type<NewModulePositionHandler> getAssociatedType() {
// TODO Auto-generated method stub
return TYPE;
}
#Override
protected void dispatch(NewModulePositionHandler handler) {
handler.onNewModulePosition(this);
}
}
And it's time for implementation of my custom widget:
a) MyComp.java
import com.google.gwt.event.shared.GwtEvent;
public class NewModulePositionEvent extends GwtEvent<NewModulePositionHandler> {
private static final Type<NewModulePositionHandler> TYPE = new Type<NewModulePositionHandler>();
private final String m_Color;
public NewModulePositionEvent(String color) {
m_Color = color;
}
public static Type<NewModulePositionHandler> getType() {
return TYPE;
}
public String getColor() {
return m_Color;
}
#Override
public com.google.gwt.event.shared.GwtEvent.Type<NewModulePositionHandler> getAssociatedType() {
// TODO Auto-generated method stub
return TYPE;
}
#Override
protected void dispatch(NewModulePositionHandler handler) {
handler.onNewModulePosition(this);
}
}
b) MyCompClientRpc.java
import com.vaadin.shared.communication.ClientRpc;
public interface MyCompClientRpc extends ClientRpc {
// TODO example API
public void alert(String message);
public void changeColor(String color);
}
c) MyCompConnector.java
package com.example.locator.widgetset.client.mycomp;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.shared.ui.Connect;
import com.example.locator.MyComp;
import com.example.locator.NewModulePositionEvent;
import com.example.locator.NewModulePositionHandler;
import com.example.locator.widgetset.client.mycomp.MyCompWidget;
import com.example.locator.widgetset.client.mycomp.MyCompServerRpc;
import com.vaadin.client.communication.RpcProxy;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.example.locator.widgetset.client.mycomp.MyCompClientRpc;
import com.example.locator.widgetset.client.mycomp.MyCompState;
import com.vaadin.client.communication.StateChangeEvent;
#Connect(MyComp.class)
public class MyCompConnector extends AbstractComponentConnector {
MyCompServerRpc rpc = RpcProxy
.create(MyCompServerRpc.class, this);
public MyCompConnector() {
registerRpc(MyCompClientRpc.class, new MyCompClientRpc() {
public void alert(String message) {
// TODO Do something useful
Window.alert(message);
}
public void changeColor(String color) {
getWidget().InitMap(color);
}
});
// TODO ServerRpc usage example, do something useful instead
getWidget().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
final MouseEventDetails mouseDetails = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(),
getWidget().getElement());
rpc.clicked(mouseDetails);
}
});
getWidget().addNewModulePositionHandler(new NewModulePositionHandler() {
public void onNewModulePosition(NewModulePositionEvent event) {
// TODO Auto-generated method stub
rpc.newModulePosition(event.getColor());
}
});
}
#Override
protected Widget createWidget() {
return GWT.create(MyCompWidget.class);
}
#Override
public MyCompWidget getWidget() {
return (MyCompWidget) super.getWidget();
}
#Override
public MyCompState getState() {
return (MyCompState) super.getState();
}
#Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
// TODO do something useful
final String color = getState().color;
getWidget().InitMap(color);
}
}
d) MyCompServerRpc.java
package com.example.locator.widgetset.client.mycomp;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.communication.ServerRpc;
public interface MyCompServerRpc extends ServerRpc {
// TODO example API
public void clicked(MouseEventDetails mouseDetails);
public void newModulePosition(String color);
}
e) MyCompState.java
package com.example.locator.widgetset.client.mycomp;
public class MyCompState extends com.vaadin.shared.AbstractComponentState {
// TODO example state
public String color = "#000000";
}
And finally implementation of the widget:
f) MyCompWidget.java
package com.example.locator.widgetset.client.mycomp;
import org.vaadin.gwtgraphics.client.DrawingArea;
import org.vaadin.gwtgraphics.client.Line;
import org.vaadin.gwtgraphics.client.shape.Circle;
import org.vaadin.gwtgraphics.client.shape.Rectangle;
import com.example.locator.HasNewModulePositionHandlers;
import com.example.locator.NewModulePositionEvent;
import com.example.locator.NewModulePositionHandler;
import com.google.gwt.dev.util.collect.HashMap;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.touch.client.Point;
import com.example.locator.Module;
// TODO extend any GWT Widget
public class MyCompWidget extends DrawingArea implements HasNewModulePositionHandlers {
public static final String CLASSNAME = "mycomp";
public static double m_AreaWidth = 64.355;
public static double m_AreaHeight = 17.385;
public static int m_PictureWidth;
public static int m_PictureHeight;
public static double m_AreaToMapRatio;
public static double m_RouteWidth = 3.5;
public static double m_MainRouteCoordinateY = 8.0828;
public Circle circle;
//public HashMap<Integer, Module> ModuleMap = new HashMap<Integer, Module>();
public MyCompWidget(){
super(640, 320);
//ModuleMap.put(666, new Module(666, 30.0, 8.08, new Circle((int)TranslateCoordinate(30.0), (int)TranslateCoordinate(8.0), 7)));
//ModuleMap.put(15, new Module(15, 27.0, 8.08, new Circle((int)TranslateCoordinate(30.0), (int)TranslateCoordinate(8.0), 7)));
double xRatio = m_AreaWidth / 640;
double yRatio = m_AreaHeight / 320;
m_AreaToMapRatio = xRatio > yRatio ? xRatio : yRatio;
InitMap("#919491");
setStyleName(CLASSNAME);
}
public void InitMap(String color)
{
m_PictureWidth = (int)TranslateCoordinate(m_AreaWidth);
m_PictureHeight = (int)TranslateCoordinate(m_AreaHeight);
Rectangle rectangle = new Rectangle(0, 0, m_PictureWidth, m_PictureHeight);
rectangle.setFillColor(color);
add(rectangle);
Point point1Beg = new Point(0.0, 8.0828);
Point point1End = new Point(64.355, 8.0838);
Point point2Beg = new Point(20.2825, 8.0828);
Point point2End = new Point(20.2825, 17.385);
Point point3Beg = new Point(59.325, 0.0);
Point point3End = new Point(59.325, 8.0828);
point1Beg = TranslatePoint(point1Beg);
point1End = TranslatePoint(point1End);
point2Beg = TranslatePoint(point2Beg);
point2End = TranslatePoint(point2End);
point3Beg = TranslatePoint(point3Beg);
point3End = TranslatePoint(point3End);
Line line1 = new Line((int)point1Beg.getX(), (int)point1Beg.getY(), (int)point1End.getX(), (int)point1End.getY());
Line line2 = new Line((int)point2Beg.getX(), (int)point2Beg.getY(), (int)point2End.getX(), (int)point2End.getY());
Line line3 = new Line((int)point3Beg.getX(), (int)point3Beg.getY(), (int)point3End.getX(), (int)point3End.getY());
line1.setStrokeColor("#FFFFFF");
line2.setStrokeColor("#FFFFFF");
line3.setStrokeColor("#FFFFFF");
line1.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));
line2.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));
line3.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));
add(line1);
add(line2);
add(line3);
DrawWall(TranslateCoordinate(10.0));
DrawWall(TranslateCoordinate(20.0));
DrawWall(TranslateCoordinate(30.0));
DrawWall(TranslateCoordinate(40.0));
DrawWall(TranslateCoordinate(50.0));
DrawWall(TranslateCoordinate(60.0));
DrawDoor(3.0, 3.0);
DrawDoor(13.0, 3.0);
DrawDoor(23.0, 3.0);
DrawDoor(33.0, 3.0);
DrawDoor(43.0, 3.0);
DrawDoor(53.0, 3.0);
circle = new Circle((int)TranslateCoordinate(25.0), (int)TranslateCoordinate(8.0), 15);
add(circle);
}
public void DrawWall(double a_Place)
{
Line line = new Line((int)a_Place, 0, (int)a_Place, (int)TranslateCoordinate(m_AreaHeight));
line.setStrokeColor("#FFFFFF");
add(line);
}
public void DrawDoor(double a_Position, double a_Width)
{
double realDoorPositionY = m_MainRouteCoordinateY - (m_RouteWidth / 2);
int doorPositionYTop = (int)TranslateCoordinate(realDoorPositionY) - 1;
int doorPositionYBottom = (int)TranslateCoordinate(realDoorPositionY + m_RouteWidth) + 1;
Line line = new Line((int)TranslateCoordinate(a_Position), doorPositionYTop, (int)TranslateCoordinate(a_Position) + (int)TranslateCoordinate(a_Width), doorPositionYTop);
line.setStrokeColor("#000000");
line.setStrokeWidth(2);
add(line);
Line line2 = new Line((int)TranslateCoordinate(a_Position), doorPositionYBottom, (int)TranslateCoordinate(a_Position) + (int)TranslateCoordinate(a_Width), doorPositionYBottom);
line2.setStrokeColor("#000000");
line2.setStrokeWidth(2);
add(line2);
}
public Point TranslatePoint(Point a_Point)
{
Point translatedPoint = new Point(TranslateCoordinate(a_Point.getX()), TranslateCoordinate(a_Point.getY()));
return translatedPoint;
}
public double TranslateCoordinate(double a_Coordinate)
{
return (a_Coordinate) / (m_AreaToMapRatio);
}
public void Move(int id) {
//ModuleMap.get(id).GetCircle().setX(10 + circle.getX());
}
public HandlerRegistration addNewModulePositionHandler(
NewModulePositionHandler handler) {
return addHandler(handler, NewModulePositionEvent.TYPE);
}
private void someMethod() {
fireEvent(new NewModulePositionEvent("#000000"));
}
public void emulateEvent() {
someMethod();
}
}
g) HasNewModulesPositionHandlers.java
package com.example.locator;
import com.google.gwt.event.shared.HandlerRegistration;
public interface HasNewModulePositionHandlers {
// Attention! method returns HandlerRegistration, so that handler can be cancelled
public HandlerRegistration addNewModulePositionHandler(
NewModulePositionHandler handler);
}
If I compile the widgets set containing MyCompWidget and then run my application on glassfish I get the following message:
Widgetset 'com.example.locator.widgetset.LocatorWidgetset' does not contain implementation for com.example.locator.MyComp. Check its component connector's #Connect mapping, widgetsets GWT module description file and re-compile your widgetset. In case you have downloaded a vaadin add-on package, you might want to refer to add-on instructions.
If I cut
public void addNewModulePositionHandler(
NewModulePositionHandler handler) {
handlerManager.addHandler(NewModulePositionEvent.getType(), handler);
// TODO Auto-generated method stub
}
widget works properly (of course I have to comment out these lines from MyCompConnector as well):
getWidget().addNewModulePositionHandler(new NewModulePositionHandler() {
public void onNewModulePosition(NewModulePositionEvent event) {
// TODO Auto-generated method stub
rpc.newModulePosition(event.getColor());
}
});
Can anyone tell me where is the problem? It seems that compilation of the widget failes but I can't find any information about that.
Please, help me.
Thanks in advance.

Compilation problem is very clear: GWT compiler cannot fins source code for a specified java class. You add source files to GWT compiler scope in two steps:
*.java files must be accessible through classpath (eclipse gwt compiler automatically includes all source folders to classpath)
You need to tell GWT that it should consider your packages during compilation
Create .gwt.xml file in PARENT package (relative to your source files) with the following content (if your package is pkg1.pkg2.pkg3, then you should in package pkg1.pkg2 create file "Pkg3.gwt.xml", pkg = "pkg3", by convention pkg3 is typically named "client")
<module>
<source path="pkg3" />
</module>
!!!Be careful with letter cases, By convention those are the correct names.
Add to your widgetset.gwt.xml file "inherits" directive like that
<inherits name="pkg1.pkg2.Pkg3" />
!!! Pay attention to letter cases (P is capital in Pkg3, after file name Pkg3.gwt.xml), .gwt.xml is omitted here
Then, first of all, Vaadin uses GWT with a certain twist. I would recommend browsing through custom widgetset samples. You may need to understand how to propagate events to and from Vaadin-specific components. Below I explain how GWT event are supposed to be implemented and used. I'm not an expert in Vaadin, especially in advanced topics such as customizing widgetsets.
So, speaking of GWT.
Basically, you need to understand only two things to make (non-DOM, also knows as bitless) events work in GWT.
Code support
Event class. NewModulePositionEvent in your case.
Event Handler interface. NewModulePositionHandler in your case.
Feature interface (optional but advised). HasNewModulePositionHandlers in your case.
Usage pattern
Basically, the component that is supposed to fire event should create relevant Event object and pass it to the fireEvent method. All the logic to invoke necessary habdler is provided by EventBus (internally)
If you need to provide API to fire events externally (such as click() method for a Button), it should be done by providing special methods (do not expose internal stuff how exactly event is fired)
DOM events are special in details how they are created (by browser) and dispatched (they need to be explicitly enabled). Anyway, all the browser events are already implemented in GWT out of the box.
So, typical implementations for the above items: For the sake of clarity, I provide excerpts from our production code.
1) Event class
public class QuestionClickEvent extends GwtEvent<QuestionClickHandler> {
public QuestionClickEvent(SScript script, SQuestion question) {
super();
this.script = script;
this.question = question;
}
public static final Type<QuestionClickHandler> TYPE = new Type<QuestionClickHandler>();
// internal event state
private final SScript script;
private final SQuestion question;
#Override
public Type<QuestionClickHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(QuestionClickHandler handler) {
handler.onQuestionClicked(this);
}
// provide access to internal event state
public SScript getScript() {
return script;
}
public SQuestion getQuestion() {
return question;
}
}
2) Handler interface
public interface QuestionClickHandler extends EventHandler {
public void onQuestionClicked(QuestionClickEvent event);
}
3) Feature interface
public interface HasQuestionClickHandlers {
// Attention! method returns HandlerRegistration, so that handler can be cancelled
public HandlerRegistration addQuestionClickHandler(
QuestionClickHandler handler);
}
4) Your widget/component
public class SummaryPanel extends Widget implements HasQuestionClickHandlers {
// blah-blah-blah
// implement your handler registration method
#Override
public HandlerRegistration addQuestionClickHandler(
QuestionClickHandler handler) {
return addHandler(handler, QuestionClickEvent.TYPE);
}
// blah-blah-blah
private someMethod() {
// suddenly you realized that you need to to fire your event
fireEvent(new QuestionClickEvent(script, question));
}
// sample external API method
public void emulateEvent() {
someMethod();
}
}
And finally usage example:
SummaryPanel summary = new SummaryPanel();
summary.addQuestionClickHandler(new QuestionClickHandler() {
#Override
public void onQuestionClicked(QuestionClickEvent event) {
// your reaction goes here
}
});

Related

What are the alternatives to RCTEventEmitter and RCTModernEventEmitter?

I am trying to integrate a Native UI component in react-native using the new architecture with fabric enabled
Here is my spec file
import type {HostComponent, ViewProps} from 'react-native';
import type {
DirectEventHandler,
BubblingEventHandler,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type Event = Readonly<{
text?: string;
}>;
interface NativeProps extends ViewProps {
text: string;
onClickHandler?: DirectEventHandler<Event>; ////Event name should start with on
}
export default codegenNativeComponent<NativeProps>(
'MyButtonView',
) as HostComponent<NativeProps>;
Then on native side I created following files
public class MyButtonViewManager extends SimpleViewManager<MyButtonView> {
public static final String NAME = "MyButtonView";
ReactApplicationContext mCallerContext;
public MyButtonViewManager(ReactApplicationContext reactContext) {
mCallerContext = reactContext;
}
#NonNull
#Override
public String getName() {
return NAME;
}
#NonNull
#Override
protected MyButtonView createViewInstance(#NonNull ThemedReactContext reactContext) {
return new MyButtonView(reactContext);
}
#ReactProp(name = "text")
public void setQrCodeText(MyButtonView view, String text) {
view.setText(text);
}
#Nullable
#Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of("topOnClickHandler",
MapBuilder.of("registrationName", "onClickHandler")
);
}
}
public class MyButtonView extends androidx.appcompat.widget.AppCompatButton {
public MyButtonView(Context context) {
super(context);
configureViews();
}
private void configureViews(){
setBackgroundColor(Color.YELLOW);
setOnClickListener(view -> {
ReactContext reactContext = (ReactContext)getContext();
EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(
reactContext ,getId()
);
eventDispatcher.dispatchEvent(new MyButtonClickEvent(getId()));
});
}
}
public class MyButtonClickEvent extends Event<MyButtonClickEvent> {
public MyButtonClickEvent(int viewId) {
super(viewId);
}
#Override
public String getEventName() {
return "topOnClickHandler";
}
#Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
super.dispatch(rctEventEmitter);
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), Arguments.createMap());
}
#Nullable
#Override
protected WritableMap getEventData() {
WritableMap event = Arguments.createMap();
event.putString("message", "MyMessage");
return event;
}
}
What is the alternative to dispatch and RCTEventEmitter as both are deprecated? I was looking into RCTModernEventEmitter and it also extends the deprecated RCTEventEmitter
Also i have to change the event name from OnClickHandler to topOnClickHandler in Native Android side. It was throwing hermes error. Not sure why there should be top prefix, why can't it just be OnClickHandler.
From the react-native source code:
This [RCTModernEventEmitter] is a transitional replacement for RCTEventEmitter that works with Fabric and non-Fabric renderers. RCTEventEmitter works with Fabric as well, but there are negative perf implications and it should be avoided.
You can use this for now as a replacement that works with Fabric.
This [RCTModernEventEmitter] interface will also be deleted in the distant future and be replaced with a new interface that doesn't need the old receiveEvent method at all. But for the foreseeable future, this is the recommended interface to use for EventEmitters.
However, in the long run this will be removed.
There's ReactEventEmitter that might help based on your use-case.

How to call Java string in React Native and display it in real time

I created string in java:
import java.lang.Math;
import java.io.*;
import java.util.*;
public class Test {
public int measureConcentration(double[] means){
return (int) ((means[3] / means[1]) * 100) ;
}
public static void main(String[] args) {
int score = measureConcentration(bandMeans);
String ratio = Integer.toString(score);
// Print values
System.out.println(String.valueOf(ratio));
I would like to display it in react native. But when I try to compile app in powershell I receive an error due to cannot find symbol int score = measureConcentration(bandMeans);.
What am I doing wrong?
I've followed React Native docs https://facebook.github.io/react-native/docs/native-modules-android.html#callbacks to create Android native module.
To expose a method to JavaScript a Java method must be annotated using #ReactMethod. The return type of bridge methods is always void. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events
public class TestBridge extends ReactContextBaseJavaModule {
public TestBridge(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public String getName() {
return "TestBridge";
}
#ReactMethod
public void getString(Callback stringCallback) {
stringCallback.invoke("Native module String");
}
}
and
public class TestBridgePackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new TestBridge(reactContext));
return modules;
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
insert my package in MainApplication
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
...
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new TestBridgePackage()
);
}
...
};
...
}
And then get a string on React Native side with callback
import {NativeModules} from 'react-native';
export default class App extends Component<Props> {
componentWillMount() {
const TestBridge = NativeModules.TestBridge;
TestBridge.getString(string => console.log(string));
}
}
Have you tried
import android.util.Log;
and then using
Log.d("first string goes here", "second string goes here");

Java - Can't access arraylist in another class

I have a runnable class "TemperatureSensor" which is periodically adding a new randomized floating point value to an array list TemperatureList as an object Temperature. The last added object in the array (index 0) is then sent from RMI client to RMI server - this happens without problems.
However, when I click a button on GUI to display the size of this object array, I always get a 0. If I print out the size of the array from RMI client class, it shows a correct size.
My question is, how do I access the same array from multiple classes correctly?
Here is the UML:
TemperatureSensor:
import java.text.DecimalFormat;
import java.util.Random;
public class TemperatureSensor implements Runnable
{
private int waitingTime;
private Model model;
public TemperatureSensor(Model model, int waitingTime)
{
this.model = model;
this.waitingTime = waitingTime;
}
#Override
public void run()
{
float temperature = 25.0f;
while(true)
{
temperature = measureTemperature(temperature);
model.addTemperatureData(temperature);
System.out.println("Sending: " + temperature);
waiting();
}
}
private float measureTemperature(float temperature)
{
Random rand = new Random();
float minTempFloat = 0.1f;
float maxTempFloat = 0.2f;
int incrementSwitch = rand.nextInt(3-0) + 0;
if (incrementSwitch == 0)
{
temperature += minTempFloat + rand.nextFloat() * (maxTempFloat - minTempFloat);
}
else if(incrementSwitch == 1)
{
//Do nothing
}
else if (incrementSwitch == 2)
{
temperature -= minTempFloat + rand.nextFloat() * (maxTempFloat -
minTempFloat);
}
return temperature;
}
private void waiting()
{
try
{
Thread.sleep(waitingTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
Model:
public interface Model
{
public void addTemperatureData(float value);
public Temperature getLatestTemperatureData();
public int getTempListSize();
}
ModelManager:
public class ModelManager implements Model
{
private TemperatureList temperatureList;
public ModelManager()
{
temperatureList = new TemperatureList();
}
#Override
public void addTemperatureData(float value)
{
Temperature temperature = new Temperature(value);
//this.temperatureList.clearTemperatureDataList();
this.temperatureList.addTemperatureDataToList(temperature);
}
#Override
public Temperature getLatestTemperatureData()
{
return temperatureList.getLatestTemperatureDataFromList();
}
#Override
public int getTempListSize()
{
return temperatureList.size();
}
}
RMIsensorClient:
import java.rmi.Naming;
import java.rmi.RemoteException;
public class RMIsensorClient
{
private RMIserverInterface serverInterface;
private static Model model = new ModelManager();
public static void main(String[] args) throws RemoteException, InterruptedException
{
TemperatureSensor tempSensor = new TemperatureSensor(model, 5000);
Thread tempThread = new Thread(tempSensor, "TempSensor");
tempThread.start();
RMIsensorClient sensorClient = new RMIsensorClient();
}
public RMIsensorClient() throws RemoteException
{
super();
try
{
serverInterface = (RMIserverInterface) Naming.lookup("rmi://localhost:1099/rmiServer");
while(true)
{
serverInterface.getTemperature(model.getLatestTemperatureData());
System.out.println(model.getTempListSize());
Thread.sleep(5000);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Controler:
public class Controller
{
private static Model model;
public Controller ()
{
this.model = new ModelManager();
}
public int getNumberOfListElements()
{
return model.getTempListSize();
}
}
GUI:
public class GUItemperatureController implements Initializable
{
private Controller controller = new Controller();
#FXML
private Label tlTemperature;
#FXML
private Pane mainPane;
#FXML
private TextField tfTemperature;
#FXML
private Button btnUpdate;
#Override
public void initialize(URL arg0, ResourceBundle arg1)
{
tfTemperature.setEditable(false);
}
#FXML
void showArraySize(ActionEvent event)
{
tfTemperature.setText(Integer.toString(controller.getNumberOfListElements()));
}
}
TemperatureList:
import java.io.Serializable;
import java.util.ArrayList;
public class TemperatureList implements Serializable
{
private ArrayList<Temperature> temperatureList;
public TemperatureList()
{
this.temperatureList = new ArrayList<>();
}
public void addTemperatureDataToList(Temperature temperature)
{
temperatureList.add(0,temperature);
}
public Temperature getLatestTemperatureDataFromList()
{
return this.temperatureList.get(0);
}
public void clearTemperatureDataList()
{
temperatureList.clear();
}
public int size()
{
return temperatureList.size();
}
}
Here is where I launch the GUI:
import java.rmi.RemoteException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class userMain extends Application
{
public FXMLLoader loader;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/FXMLtemperature.fxml"));
loader.setController(new GUItemperatureController());
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setTitle("GEMS - Test");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Your problem is not about classes.
You run two separate applications. One runs your RMIsensorClient and one runs your GUI. They know nothing about each other, your RMIsensorClient and your Controller have their own separate instances of ModelManager and you have no code anywhere that would share any data between them.
You need to make the data you want to show in your GUI accessible somehow.
One solution could be to use a network interface for that. Create two different ModelManagers, one that opens and listens to a ServerSocket, and one that uses a Socket in getLatestTemperatureData() to connect to the other one.
Use the former in your RMIsensorClient and the latter in your GUI's Controller.
Research networking in Java.
This is a very crude solution, but there are plenty of great tutorials for networking and sharing data between multiple Java applications.
You haven't included your TemperatureList implementation, but if as you say it's an ArrayList it's likely you're not properly synchronizing access across threads. It's imperative that you properly synchronize cross-thread work otherwise you'll wind up with some sort of undefined behavior, such as changes not propagating or data structures winding up broken.
There are a number of thread-safe collections in java.util.collect.concurrent that you might consider, otherwise you'll need to ensure you use synchronized blocks or methods anywhere you're working with this list.
The most obvious problem that I found(and this might not be all) is that your array list is method specific. it is not static. Meaning that it can only be accessed by the method it originates in. the easiest fix for this is to add a static modifier to your array list when it is created and create it outside of the methods.

Java Event Listener to detect a variable change

I cannot seem to find an answer anywhere to my question. Is there any event listener which can detect the changing of a boolean or other variable and then act on it. Or is it possible to create a custom event listener to detect this?
Please I cannot seem to find a solution to this anywhere and I found this website explaining how to create custom events
Use PropertyChangeSupport. You wont have to implement as much and it is thread safe.
public class MyClassWithText {
protected PropertyChangeSupport propertyChangeSupport;
private String text;
public MyClassWithText () {
propertyChangeSupport = new PropertyChangeSupport(this);
}
public void setText(String text) {
String oldText = this.text;
this.text = text;
propertyChangeSupport.firePropertyChange("MyTextProperty",oldText, text);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
}
public class MyTextListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals("MyTextProperty")) {
System.out.println(event.getNewValue().toString());
}
}
}
public class MyTextTest {
public static void main(String[] args) {
MyClassWithText interestingText = new MyClassWithText();
MyTextListener listener = new MyTextListener();
interestingText.addPropertyChangeListener(listener);
interestingText.setText("FRIST!");
interestingText.setText("it's more like when you take a car, and you...");
}
}
Just like you need to create an event listener, you will also need to create the event firer -- since there is nothing automatic that will do this for you. I've provided sample code that shows you how to implement such a firer.
This test implementation isn't perfect. It only includes a way to add listeners. You may wish to include a way to remove listeners who are no longer interested in receiving events. Also note that this class is not thread-safe.
import java.util.List;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.awt.EventQueue;
/**
* This class uses the EventQueue to process its events, but you should only
* really do this if the changes you make have an impact on part of a GUI
* eg. adding a button to a JFrame.
*
* Otherwise, you should create your own event dispatch thread that can handle
* change events
*/
public class BooleanChangeTest implements BooleanChangeDispatcher {
public static void main(String[] args) {
BooleanChangeListener listener = new BooleanChangeListener() {
#Override
public void stateChanged(BooleanChangeEvent event) {
System.out.println("Detected change to: "
+ event.getDispatcher().getFlag()
+ " -- event: " + event);
}
};
BooleanChangeTest test = new BooleanChangeTest(false);
test.addBooleanChangeListener(listener);
test.setFlag(false); // no change, no event dispatch
test.setFlag(true); // changed to true -- event dispatched
}
private boolean flag;
private List<BooleanChangeListener> listeners;
public BooleanChangeTest(boolean initialFlagState) {
flag = initialFlagState;
listeners = new ArrayList<BooleanChangeListener>();
}
#Override
public void addBooleanChangeListener(BooleanChangeListener listener) {
listeners.add(listener);
}
#Override
public void setFlag(boolean flag) {
if (this.flag != flag) {
this.flag = flag;
dispatchEvent();
}
}
#Override
public boolean getFlag() {
return flag;
}
private void dispatchEvent() {
final BooleanChangeEvent event = new BooleanChangeEvent(this);
for (BooleanChangeListener l : listeners) {
dispatchRunnableOnEventQueue(l, event);
}
}
private void dispatchRunnableOnEventQueue(
final BooleanChangeListener listener,
final BooleanChangeEvent event) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
listener.stateChanged(event);
}
});
}
}
interface BooleanChangeDispatcher {
public void addBooleanChangeListener(BooleanChangeListener listener);
public boolean getFlag();
public void setFlag(boolean flag);
}
/**
* Listener interface for classes interested in knowing about a boolean
* flag change.
*/
interface BooleanChangeListener extends EventListener {
public void stateChanged(BooleanChangeEvent event);
}
/**
* This class lets the listener know when the change occured and what
* object was changed.
*/
class BooleanChangeEvent extends EventObject {
private final BooleanChangeDispatcher dispatcher;
public BooleanChangeEvent(BooleanChangeDispatcher dispatcher) {
super(dispatcher);
this.dispatcher = dispatcher;
}
// type safe way to get source (as opposed to getSource of EventObject
public BooleanChangeDispatcher getDispatcher() {
return dispatcher;
}
}
you can also try to implement an Observer.
First create the observable object:
import java.util.Observable;
public class StringObservable extends Observable {
private String name;
public StringObservable(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(name);
}
}
Then the observer:
import java.util.Observable;
import java.util.Observer;
public class NameObserver implements Observer {
private String name;
public NameObserver() {
name = null;
}
public void update(Observable obj, Object arg) {
if (arg instanceof String) {
name = (String) arg;
System.out.println("NameObserver: Name changed to " + name);
} else {
System.out.println("NameObserver: Some other change to subject!");
}
}
}
And in your main (or wherever else):
public class TestObservers {
public static void main(String args[]) {
// Create the Subject and Observers.
StringObservable s = new StringObservable("Test");
NameObserver nameObs = new NameObserver();
// Add the Observer
s.addObserver(nameObs);
// Make changes to the Subject.
s.setName("Test1");
s.setName("Test2");
}
}
Mostly found here
Very late to answer, but this is a problem that can be solved with Observer/Observable. Example
The boolean you are setting should be allowed to do only through a setter method like:
public void setFlag(boolean flag){
//Method code goes here
}
Now in now set method, you can decide based on what value comes in, what event needs to be fired. I am explaining in simple terms without introducing complex terms so you can understand better, so code snippet would look like:
public void setFlag(boolean flag){
//if flag is TRUE do something
//If flag is FALSE then do something
//And finally do what you needed to do with flag
}
Ask questions if you need more info
you create a listener when you want to listen for I/O changes. mostly on graphics.
the answer to your question is to keep state of the running program, then check if variables change from the state inside the infinite loop of your program.
You can use AOP for that, perhaps AspectJ? Check a few examples here (if you use Eclipse, then using AspectJ is really simple with their plugin).
For you, you would have a pointcut similar to the one used in the SampleAspect, but one that will only be used when someone makes a new SET to a boolean variable (this doesn't mean that the value has changed, just that someone loaded a value to the variable).

Detecting a change in an integer

Is there any way to detect change in an integer? Such as creating a listener to listen to the integer to detect and change in value it has. I know this is possible with booleans with a few tricks but I cannot seem to adapt this to an int value. Does anyone have any idea how this could be done? I need to know how to do this in the Java language. Below is code that I found online that allows for a boolean listener. How can I convert this to an integer listener?
import java.util.List;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.awt.EventQueue;
//can u see this austin? can u see this i typed this at 9:33 my time
/**
* This class uses the EventQueue to process its events, but you should only
* really do this if the changes you make have an impact on part of a GUI
* eg. adding a button to a JFrame.
*
* Otherwise, you should create your own event dispatch thread that can handle
* change events
*/
public class test1 implements BooleanChangeDispatcher {
public static void main(String[] args) {
BooleanChangeListener listener = new BooleanChangeListener() { // add this to the class
#Override
public void stateChanged(BooleanChangeEvent event) {
System.out.println("Detected change to: "
+ event.getDispatcher().getFlag()
+ " -- event: " + event);
}
};
test1 test = new test1(false);
test.addBooleanChangeListener(listener);
// test.setFlag(false); // no change, no event dispatch
// test.setFlag(true); // changed to true -- event dispatched
}
private boolean flag;
private List<BooleanChangeListener> listeners;
public test1(boolean initialFlagState) {
flag = initialFlagState;
listeners = new ArrayList<BooleanChangeListener>();
}
#Override
public void addBooleanChangeListener(BooleanChangeListener listener) {
listeners.add(listener);
}
#Override
public void setFlag(boolean flag) {
if (this.flag != flag) {
this.flag = flag;
dispatchEvent();
}
}
#Override
public boolean getFlag() {
return flag;
}
private void dispatchEvent() {
final BooleanChangeEvent event = new BooleanChangeEvent(this);
for (BooleanChangeListener l : listeners) {
dispatchRunnableOnEventQueue(l, event);
}
}
private void dispatchRunnableOnEventQueue(
final BooleanChangeListener listener,
final BooleanChangeEvent event) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
listener.stateChanged(event);
}
});
}
}
interface BooleanChangeDispatcher {
public void addBooleanChangeListener(BooleanChangeListener listener);
public boolean getFlag();
public void setFlag(boolean flag);
}
/**
* Listener interface for classes interested in knowing about a boolean
* flag change.
*/
interface BooleanChangeListener extends EventListener {
public void stateChanged(BooleanChangeEvent event);
}
/**
* This class lets the listener know when the change occured and what
* object was changed.
*/
class BooleanChangeEvent extends EventObject {
private final BooleanChangeDispatcher dispatcher;
public BooleanChangeEvent(BooleanChangeDispatcher dispatcher) {
super(dispatcher);
this.dispatcher = dispatcher;
}
// type safe way to get source (as opposed to getSource of EventObject
public BooleanChangeDispatcher getDispatcher() {
return dispatcher;
}
}
I would create a class capable of registering listeners. Below is a mocked up example. It might even compile as is (assuming you write the corresponding VocalIntegerListener interface exists and is implemented somehow... it's pretty simple).
class VocalInteger {
private int value;
private final Object lock = new Object();
Set<VocalIntegerListener> listeners; // assume interface exists - it's easy
public VocalInteger() {
this(0);
}
public VocalInteger(int value) {
this.value = value;
listeners = new HashSet<VocalIntegerListener>();
}
public int getValue() {
return value;
}
public void setValue(int value) {
synchronized(lock) {
int oldValue = this.value;
this.value = value;
for(VocalIntegerListener listener : listeners) {
listener.fireChangedEvent(oldvalue, value); // assume exists
}
}
}
public void registerListener(VocalIntegerListener listener) {
synchronized(lock) {
listeners.add(listener);
}
}
}
Have a look at "Java Beans" and "bound properties" for the standard approach how to listen for property changed events:
http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html
http://docs.oracle.com/javase/tutorial/javabeans/

Categories