**I'm unable to create a constructor from "GUIController".. The program runs if i delete this line
"GUIController(){myModel = new TheModel(this)"
but i still need it in other part. Please help!
**
package theclient;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class GUIController extends Application {
TheModel myModel;
GUIController(){
myModel = new TheModel(this);
}
//public void init(){}
public TextArea myTextArea;
public TextField myTextField;
// Button and text field actions
public void myButtonAction() {
sendMsg();
}
public void myTextFieldAction() {
sendMsg();
}
// Append coming message
public void displayMsg(String comingMSG) {
System.out.println("Receive 01");
myTextArea.appendText(comingMSG);
}
public void sendMsg() {
try {
System.out.println("Send 01");
myModel.myChatServer.tellOthers(myTextField.getText());
} catch (RemoteException ex) {
Logger.getLogger(GUIController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("GUI.fxml"));
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) throws Exception {
new GUIController();
launch(args);
}
}
The Second class. I'd be thankful if you can suggest any edits to the code. Thanks in advance for your efforts.
package theclient;
import common.ChatServerInt;
import common.ClientInt;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TheModel implements ClientInt {
public GUIController myCtrl;
ChatServerInt myChatServer;
TheModel(GUIController myCtrl) {
this.myCtrl = myCtrl;
}
public ChatServerInt connection() {
if (myChatServer == null) {
try {
Registry reg = LocateRegistry.getRegistry(1111);
myChatServer = (ChatServerInt) reg.lookup("ChatService");
myChatServer.register(this);
myChatServer.tellOthers("I'm here!");
} catch (RemoteException | NotBoundException ex) {
Logger.getLogger(TheModel.class.getName()).log(Level.SEVERE, null, ex);
}
} return myChatServer;
}
#Override
public void receive(String msg) throws RemoteException {
myCtrl.displayMsg(msg);
}
}
Following the Model-view-controller design pattern, the model shouldn't be holding a reference to its controller. If the controller needs to respond to changes in the model's data, then this can be done with properties and listeners. The model holds a property (here, a StringProperty) and the controller listens for changes to the property.
For your code, this means storing the msg in a StringProperty. The controller, after constructing the model, attaches a ChangeListener that calls displayMsg when the model receives a message.
Using a property and listener, TheModel no longer stores a reference to GUIController and does not take a GUIController as a parameter in its constructor.
GUIController would look something like this:
public class GUIController extends Application {
...
TheModel myModel;
...
GUIController(){
myModel = new TheModel();
// Listen for changes in the msg StringProperty and call displayMessage when it changes
myModel.getMsgProperty().addListener(msg -> this.displayMsg(msg));
}
...
Note that the constructor for GUIController no longer needs to pass this to the constructor TheModel. (In general, avoid passing this outside of the constructor. An object is not fully constructed until the constructor returns.)
TheModel would look something like this:
public class TheModel implements ClientInt {
...
private StringProperty msgProperty;
...
// remember to add a getter and setter for msgProperty!
...
#Override
public void receive(String msg) throws RemoteException {
// When a message is received, listeners attached to msgProperty will execute when setValue is called
msgProperty.setValue(msg);
}
Related
I'm trying to add spans when constructor of some class called. I'm using opentelemetry javaagent and extensions to add tracing to my application.
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ClassConstructorInstrumentation implements TypeInstrumentation {
#Override
public ElementMatcher<TypeDescription> typeMatcher() {
return ElementMatchers
.namedOneOf("org.example.ServiceManagerDummy");
}
#Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isConstructor(),
this.getClass().getName() + "$ConstructorSpanCreateAdvice");
// transformer.applyAdviceToMethod(
// named("dummyMethod"),
// this.getClass().getName() + "$ConstructorSpanCreateAdvice");
}
#SuppressWarnings("unused")
public static class ConstructorSpanCreateAdvice {
#Advice.OnMethodEnter
public static void onEnter() {
System.out.println("START SPAN ");
}
#Advice.OnMethodExit(onThrowable = Throwable.class)
public static void onExit(
#Advice.Thrown Throwable throwable
) {
System.out.println("END SPAN ");
}
}
}
public class ServiceManagerDummy {
public ServiceManagerDummy() {
System.out.println("SERVICE MANAGER CONSTR");
dummyMethod();
}
private void dummyMethod() {
System.out.println("DUMMY METHOD CALLED");
}
}
I'm using a simple configuration as above just to verify that when the constructor was called my advice method log it. But when it configured to add some logs when the constructor was called, I received nothing in the log. But when I add config for method calling (commented code) it works. What's wrong in my configuration?
What Byte Buddy would normally do would be to wrap the constructor in a try-finally-block. For a constructor, that is not possible as the super method call cannot be wrapped in such a block. "onThrowable" is therefore not possible for constructors.
Hello so i got the following code:
Event Handler.java
package me.xenopyax.edla.watcher;
import static java.nio.file.StandardWatchEventKinds.*;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.util.ArrayList;
import java.util.List;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class EventHandler {
private Path folderPath = Paths.get(System.getProperty("user.dir") + "/Saved Games/Frontier Developments/Elite Dangerous");
private String watchFile;
private List<EventListener> listeners = new ArrayList<>();
public EventHandler() {
// We obtain the file system of the Path
FileSystem fileSystem = folderPath.getFileSystem();
// We create the new WatchService using the try-with-resources block
try (WatchService service = fileSystem.newWatchService()) {
// We watch for modification events
folderPath.register(service, ENTRY_MODIFY);
// Start the infinite polling loop
while (true) {
// Wait for the next event
WatchKey watchKey = service.take();
for (WatchEvent<?> watchEvent : watchKey.pollEvents()) {
// Get the type of the event
Kind<?> kind = watchEvent.kind();
if (kind == ENTRY_MODIFY) {
Path watchEventPath = (Path) watchEvent.context();
// Call this if the right file is involved
if (watchEventPath.toString().equals(watchFile)) {
//File has been modified, call event registered
}
}
}
if (!watchKey.reset()) {
// Exit if no longer valid
break;
}
}
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void registerListener(EventListener listener) {
listeners.add(listener);
}
}
and Main.java
package me.xenopyax.edla;
import java.io.File;
import me.xenopyax.edla.discord.EDLARPC;
import me.xenopyax.edla.watcher.EventHandler;
import me.xenopyax.edla.watcher.GameStartListener;
public class Main {
private EDLARPC edlarpc = new EDLARPC();
private File journalDir = new File(System.getProperty("user.home") + "/Saved Games/Frontier Developments/Elite Dangerous");
public static void main(String[] args) {
EventHandler handler = new EventHandler();
handler.registerListener(new GameStartListener());
}
public EDLARPC getRPC() {
return edlarpc;
}
public File getJournalDirectory() {
return journalDir;
}
and EventListener.java
package me.xenopyax.edla.watcher;
public abstract class EventListener {
public void onGameStart(){};
}
and GameStartListener.java
package me.xenopyax.edla.watcher;
public class GameStartListener extends EventListener {
#Override
public void onGameStart() {
}
}
Now my question is how do I call the abstract method from EventListener.java in EventHandler.java and how do i check in the ArrayList which methods are overridden? I am trying to create an EventHandler that listens to an file and when changes happen it looks up what changed and fires the approperiate abstract method from EventListener.java.
You can check a declaring class of a method if it's not your abstract class then the method was overridden.
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
class Main {
static abstract class EventListener {
public void onFileChanged() {
throw new NotImplementedException();
}
}
static class EventListenerNotImpl extends EventListener {
}
static class EventListenerImpl extends EventListener {
private String id;
public EventListenerImpl(String id) {
this.id = id;
}
public void onFileChanged() {
System.out.println(id + ":" + EventListenerImpl.class.getCanonicalName() + ".onFileChanged() was called");
}
}
static class EventHandler {
private List<EventListener> listeners = new ArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener);
}
private void propagateOnFileChangedEvent() {
listeners.forEach(l -> {
try {
Method m = l.getClass().getMethod("onFileChanged");
if (!m.getDeclaringClass().equals(EventListener.class)) {
l.onFileChanged();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
});
}
}
public static void main(String[] args) {
EventHandler handler = new EventHandler();
handler.addListener(new EventListenerImpl("listener-1"));
handler.addListener(new EventListenerNotImpl()); // Not will be invoked onFileChangedEvent
handler.addListener(new EventListenerImpl("listener-3"));
handler.propagateOnFileChangedEvent();
}
}
Output:
listener-1:Main.EventListenerImpl.onFileChanged() was called
listener-3:Main.EventListenerImpl.onFileChanged() was called
I am creating a JavaFX application and when I create a controller for my FXML file the constructors are always the same.
Is there any way to write a custom annotation to create my constructors?
Something like this:
public class MyClass() {
#InitFxml(file = "test")
public MyClass() {
}
And the #InitFxml would inject the following code into the constructor:
FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml");
...
or is it possible to create annotation for the class which creates this default constructor?
Any help is greatly appreciated.
To process the annotation, you would have to define some kind of container that processed it, and always load your class through that container, or define an annotation processor which you attached to the compiler (I think: I know nothing about that second option).
Why not just pass a string as a parameter, though. You could define an interface:
import java.net.URL;
import javafx.fxml.FXMLLoader;
public interface CustomComponent {
public default void loadFXML(String fxml) {
try {
URL resource = getClass().getResource(fxml);
FXMLLoader loader = new FXMLLoader(resource);
loader.setRoot(this);
loader.setController(this);
loader.load();
} catch (Exception exc) {
if (! (exc instanceof RuntimeException)) {
throw new RuntimeException(exc);
} else {
throw (RuntimeException)exc ;
}
}
}
}
and then just have your custom components implement it, calling the method from the constructor:
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CustomComponentTest extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new CustomVBox(), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class CustomVBox extends VBox implements CustomComponent {
#FXML
private Label label ;
public CustomVBox() {
loadFXML("CustomVBox.fxml");
}
#FXML
private void click() {
System.out.println("Click!");
}
}
public static void main(String[] args) {
launch(args);
}
}
This seems to be no heavier than defining an annotation on an empty constructor.
I'm trying to implement TextFX in my project to do some UI testing. However it seems I can't get it to work properly. I've downloaded the jars from http://search.maven.org/#search%7Cga%7C1%7Ctestfx to a folder named 'TestFX-3.1.2' on my system.
Afterwards I've created a new library in Netbeans8 pointing to those jar files (jar, source and javadoc). As a matter of test I've created a simple Java FXML project with the new library added.
public class Test2 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Next to that I have a controller for my FXML file with the following generated code:
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
To implement the TestFX side, I've created a new class that extends GuiTest:
package test2;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import org.loadui.testfx.GuiTest;
public class TestTheThing extends GuiTest {
#Override
protected Parent getRootNode() {
FXMLLoader loader = new FXMLLoader();
Parent node = null;
try {
node = loader.load(this.getClass().getResource("FXMLDocument.fxml").openStream());
} catch (IOException e) {
System.out.println(e.toString());
}
return node;
}
#Test //<-- this Annotiation does not work
public void pressTheButton(){
//TODO
}
}
As said above in the code, the #Test simply does not work and is red underlined with the warning 'cannot find symbol'. Could anyone point me in the right direction about what I'm doing wrong?
According to https://repo1.maven.org/maven2/org/loadui/testFx/3.1.2/testFx-3.1.2.pom, testFx has several dependencies (guava, junit, hamcrest-all, hamcrest-core). To work correctly, you need to add the jars corresponding to these dependencies to your project. However, using maven is the recommended approach for that.
Don't load your fxml file directly in the test class as it may not work intentionally. Instead launch main class this way:
FXTestUtils.launchApp(Test2.class);
Thread.sleep(2000);
controller = new GuiTest()
{
#Override
protected Parent getRootNode()
{
return Test2.getStage().getScene().getRoot();
}
};
Create a static method getStage() in your Test2 class that returns the Stage. The above code should reside in a method annoted with #BeforeClass in your test class. The controller is a static reference to the GuiTest.
In the end your test class should look something like this:
import java.io.IOException;
import javafx.scene.Parent;
import org.loadui.testfx.GuiTest;
import org.loadui.testfx.utils.FXTestUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestTheThing
{
public static GuiTest controller;
#BeforeClass
public static void setUpClass() throws InterruptedException, IOException
{
FXTestUtils.launchApp(Test2.class);
Thread.sleep(2000);
controller = new GuiTest()
{
#Override
protected Parent getRootNode()
{
return Test2.getStage().getScene().getRoot();
}
};
}
#Test
public void testCase()
{
System.out.println("in a test method");
}
}
In this case you will not need to extend from GuiTest. And, don't forget to create static getStage() in Test2 class. Hope this will help. This is working fine in my case.
I have simple main class.
There i try pass user to WindowLogin :
package client;
public class Client{
public User user;
public static void main(String[] args) {
try {
Client client = new Client();
client.run(args);
} catch (Exception e) {
System.out.println("[ERR] Fatal error");
}
}
public void run(String[] args)
{
user = new User();
WindowLogin windowLogin = new WindowLogin();
windowLogin.user = user;
windowLogin.show();
}
}
Window main class. There i try call test() function of user (in real, i need it pass to WindowMainController):
package client;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Parent;
import java.io.IOException;
public class WindowLogin extends Application{
private Stage stage;
public User user;
#Override
public void start(Stage primaryStage) throws Exception {
stage = new Stage();
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("views/WindowLogin.fxml"));
WindowLoginController controller =
fxmlLoader.<WindowLoginController>getController();
user.test();
Parent root = fxmlLoader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void show(){
launch();
}
public void hide() { stage.hide(); }
}
When i try to run it all:
Exception in Application start method
Of course (maybe :) ) it because of user in windowLogin is null.
What i doing wrong? How pass user to windowLogin? (i wont use Singletone)
Update:
I need use user in start() method, as i said before - i need pass user to WindowMainController
OverView
The problem you are facing here is on calling launch(), Javafx thread creates a new object of WindowLogin. So the object that you have created for WindowLogin and assigned user to it is no longer used in the start method !
WindowLogin windowLogin = new WindowLogin();
windowLogin.user = user;
You can overcome this by declaring the User in WindowLogin as static !
public static User user;
This will help to just keep on instance of the User