I have a JTextArea always visible in my main app window (a Log if you like), and I want to use it to display activity going on in the system (like mock-debug output you'd do with System.out.println() in if conditions or whatever)
I mean high level things the user does, (like "successfully loaded file " or " written to disk", " completed" etc)
Thing is such messages can be generated anywhere in my system mainly in another package the classes of which deal with the data and computation, and they're unaware of the GUI.
Maybe save the messages to a temp file and the textarea "monitors" that file for changes, how can this be done?
The simplest way is to define a logger interface:
package com.example.logging;
public interface ActivityLogger {
void logAction(String message);
}
Then pass it to your non-GUI components so they don't get tied to a specific implementation:
public class FileLoader {
private ActivityLogger logger;
public FileLoader(ActivityLogger logger){
this.logger = logger;
}
public void loadFile(){
// load stuff from file
logger.logAction("File loaded successfully");
}
}
Now, making an implementation that writes to a text component is simple:
public class TextComponentLogger implements ActivityLogger{
private final JTextComponent target;
public TextComponentLogger(JTextComponent target) {
this.target = target;
}
public void logAction(final String message){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
target.setText(String.format("%s%s%n",
target.getText(),
message));
}
});
}
}
// Usage:
JTextArea logView = new JTextArea();
TextComponentLogger logger = new TextComponentLogger(logView);
FileLoader fileLoader = new FileLoader(logger);
fileLoader.loadFile();
You can of course also use a standard logging framework (java.util.logging, slf4j, log4j, etc) and write an appender that "writes" to a text component.
The design can be rather complicated. Maybe you can have a public access method like updateText() in the class where your TextArea would be. Then you create a kind of 'resource' or 'shared' class (just a plain class) that would be initialized together when your main() runs. When the class containing your TextArea is created, an instance would be placed into the 'shared' class (this shared class should be a singleton) and so all the other classes call this 'shared' class (maybe a method like updateTextArea()) and what it would do is call the class containing the TextArea via that instance and call the TextArea to update text.
The Message Console might be what you are looking for.
Java also has a "Logger" API.
You can use EventBus to decouple your GUI from the other parts of your application. (My blog has another introduction). You could do something as follows:
public class LogArea extends JTextArea {
public static final String LOG_TOPIC = "logarea_topic";
public LogArea() {
super();
// Read in the annotations, register self as a listener to the topic
AnnotationProcessor.process(this);
}
#EventTopicSubscriber(topic=LOG_TOPIC)
public void logEvent(String topic, String text) {
append(text + "\n");
}
}
public class DomainClass {
public void foo() {
// Send out a notification throughout the system to whichever components
// are registered to handle this topic.
EventBus.publish(LogArea.LOG_TOPIC, "some text you want to appear in the log area");
}
}
In a real system you'd probably want to move the topic declarations to another class so that one can use it without being tied to a specific implementation. E.g. you could have a Topics class that just contains the static string constants of the topics. Then you can have multiple classes that listen to those topics and process the messages (e.g. you could have a standard logging framework which writes out to a log file in addition to the jtextarea component).
Related
I'm searching for a concept to forward an object to subobjects.
Example:
I would like to create log files for several main Objects, that include sub objects (imagine a REST server that would log every single connection by ID).
Creating one big log file is simple ( redirect System.out.println, I already encapsulated that)
Example code:
class SubElementA{
public SubElementA(){
Debugger.debug("I am called, too");
}
}
Application.java
package com.dev4ag;
class Application{
private ElementA elA;
private String prefix;
public Application(String name){
this.elA = new ElementA();
this.prefix = name;
}
public void countUp(){
Debugger.debug(this.prefix+": I will now count up");
this.elA.doSomeStuff();
}
}
ElementA.java
package com.dev4ag;
class ElementA{
private int counter;
private SubElementA subElementA;
public void doSomeStuff(){
counter++;
Debugger.debug("Counter is: "+counter);
}
//Constructor
public ElementA(){
subElementA = new SubElementA();
this.counter = 0;
};
}
SubElementA.java
package com.dev4ag;
class SubElementA{
public SubElementA(){
Debugger.debug("I am called, too");
}
}
Debugger.java
package com.dev4ag;
public class Debugger {
public static void debug(String output){
//Just imagine we would write to a file here ;)
System.out.println(output);
}
}
(it was more easy to write system.out.println than to create a file, just imagine, Debugger.debug would write to a file).
Now I am thinking about a solution to create one Debug output target for each App. I could definitely change debug to not being static and create a debug object within Application.
But is there any way to use this object in the sub classes without forwarding the debug object either through Constructor or setter function, which would mean to have to add an object for the debugger to each class?
What would be the most beautiful solution for that?
Note that this solution might decrease performance a lot and it is pretty dirty way, but some loggers include such data.
But you can use Thread.currentThread().getStackTrace() to get stacktrace like in error and get class and method from where your method was called.
If you are using java9+ then you should probably use StackWalker API instead, especially that it have nice filters and other useful features.
So then you could guess app by class/method names on the stack.
I'm trying to develop a little drag & drop application under Java FX. User will drop JFX components like Buttons, Menus, Labels on certain positions. When done, he will save this layout and later on he will reopen the layout and he will use it again.
Its important to store the information about all objects that are dropped on some position.
I decided to use serialization for this purpose. But I'm not able to serialize JavaFX components. I tried to serialize Buttons, Scenes, Stages, JFXPane but nothing seemed to work (I obtained NotSerializableException).
Any suggestions how to save all the components and then retrieve them ?
P.S.: I was trying to find out some method with FXML but I did not succeed.
Thank you very much for your answers :)
You are correct, JavaFX (as of 2.1) does not support serialization of components using the Java Serializable interface - so you cannot use that mechanism.
JavaFX can deserialize from an FXML document using the FXMLLoader.load() method.
The trick though, is how to write your existing components and states out to FXML?
Currently, there is nothing public from the platform which performs FXML serialization. Apparently, creating a generic scenegraph => FXML serializer is quite a complex task (and there is no public 3rd party API for this that I know of). It wouldn't be too difficult to iterate over the scenegraph and write out FXML for a limited set of components and attributes.
If the main goal of saving user components on the servers side - is to have a possibility to show the same interface to the user - why not to save all descriptive information you need about users components, and when it is needed - just rebuild user interface again, using stored descriptive information? Here is primitive example:
/* That is the class for storing information, which you need from your components*/
public class DropedComponentsCoordinates implements Serializable{
private String componentID;
private String x_coord;
private String y_coord;
//and so on, whatever you need to get from yor serializable objects;
//getters and setters are assumed but not typed here.
}
/* I assume a variant with using FXML. If you don't - the main idea does not change*/
public class YourController implements Initializable {
List<DropedComponentsCoordinates> dropedComponentsCoordinates;
#Override
public void initialize(URL url, ResourceBundle rb) {
dropedComponentsCoordinates = new ArrayList();
}
//This function will be fired, every time
//a user has dropped a component on the place he/she wants
public void OnDropFired(ActionEvent event) {
try {
//getting the info we need from components
String componentID = getComponentID(event);
String component_xCoord = getComponent_xCoord(event);
String component_yCoord = getComponent_yCoord(event);
//putting this info to the list
DropedComponentsCoordinates dcc = new DropedComponentsCoordinates();
dcc.setX_Coord(component_xCoord);
dcc.setY_Coord(component_yCoord);
dcc.setComponentID(componentID);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getComponentID(ActionEvent event){
String componentID;
/*getting cpmponentID*/
return componentID;
}
private String getComponent_xCoord(ActionEvent event){
String component_xCoord;
/*getting component_xCoord*/
return component_xCoord;
}
private String getComponent_yCoord(ActionEvent event){
String component_yCoord;
/*getting component_yCoord*/
return component_yCoord;
}
}
I can't get my head round this one. I've tried to adhere to the MVC pattern for the first time and now have difficulties accessing the source of an ActionEvent because the ActionListener is located in a different class. But let the code do the talking...
In the "view":
// ControlForms.java
...
private JPanel createSearchPanel() throws SQLException {
...
comboBoxCode = new JComboBox(); // Field comboBoxCode -> JComboBox()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
AutoCompleteSupport<Object> support = AutoCompleteSupport.install(
comboBoxCode, GlazedLists.eventListOf(jnlCodeArray));
}
}); // Auto-Complete comboBox from GlazedLists
...
public void setComboListener(ComboListener comboListener) {
comboBoxCode.addActionListener(comboListener);
}
...
}
Then, in what I term the controller, I have two different classes:
// Controller.java
public MyController() throws SQLException {
...
addListeners();
}
...
private void addListeners(){
View view = getView();
getView().getControlForm().setComboListener(new ComboListener());
}
and
public class ComboListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("ComboBox listened to! e = " + e.toString());
}
}
Now, e obviously doesn't give the name of the variable (which at the moment I wish it would), so I cannot if test for e.getSource().
My question is thus: is there either a) a way to query (via if for example) the source of e, or b) a less complicated way to get to the variable name?
Many, many thanks in advance for your insights and tips!
Why do you need the name of the variable? Why can't you do the event handling like this
public class ComboListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JComboBox source = (JComboBox)e.getSource();
//do processing here
}
}
I'd think that if you need to do processing according the variable name, obviously you need different listeners for different combo boxes.
Generally, there are only two situations in which you should use a listener like that: a) you're going to handle a certain event the same way for a bunch of objects, or b) you're only going to use the listener for one object. In the latter case, I'd prefer handling the event locally anyway.
That said, the direct answer to your question is: you shouldn't have to check inside your ActionListener implementation to see whether the appropriate object is the source of the event; you should simply only add the ActionListener to that one object.
One final note: without knowing the specifics of your architecture... generally, MVC will treat all event handling as part of the View (it reduces coupling) and the View will pass commands or method calls or your own events (i.e., not Swing's) to the Controller.
I wonder how to use the EventBus or whether there are some better solutions to send an Event through the project.
Widget1 has a Button. Widget2 has a Label, that should change when I press the button. These widgets are in a DockLayout:
RootLayoutPanel rootLayoutPanel = RootLayoutPanel.get();
DockLayoutPanel dock = new DockLayoutPanel(Unit.EM);
dock.addWest(new Widget1(), 10);
dock.add(new Widget2());
rootLayoutPanel.add(dock);
I have declared an handleClickAlert in Widget1:
#UiHandler("button")
void handleClickAlert(ClickEvent e) {
//fireEvent(e);
}
When you divide the project into logical parts (for example with MVP), then the different parts sometimes need to communicate. Typical this communication is done by sending status changes, e.g.:
user logged-in / logged-out.
user navigated directly via URL to a page, so the menu needs to be updated.
Using the event bus is quite logical in those cases.
To use it you instantiate one EventBus per app which is then used by all other classes. To achieve this use a static field, factory or dependency injection (GIN in case of GWT).
Example with your own event types:
public class AppUtils{
public static EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);
}
Normally you'd also create your own event types and handlers:
public class AuthenticationEvent extends GwtEvent<AuthenticationEventHandler> {
public static Type<AuthenticationEventHandler> TYPE = new Type<AuthenticationEventHandler>();
#Override
public Type<AuthenticationEventHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(AuthenticationEventHandler handler) {
handler.onAuthenticationChanged(this);
}
}
and the handler:
public interface AuthenticationEventHandler extends EventHandler {
void onAuthenticationChanged(AuthenticationEvent authenticationEvent);
}
Then you use it like this:
AppUtils.EVENT_BUS.addHandler(AuthenticationEvent.TYPE, new AuthenticationEventHandler() {
#Override
public void onAuthenticationChanged(AuthenticationEvent authenticationEvent) {
// authentication changed - do something
}
});
and fire the event:
AppUtils.EVENT_BUS.fireEvent(new AuthenticationEvent());
While simple, interface-driven event notification frameworks in Java have been around since pre-Cambrian times (e.g. java.beans.PropertyChangeSupport), it is becoming increasingly popular for frameworks to use annotation-driven event notification instead.
For an example, see JBossCache 2.2. The listener class has its listener methods annotated, rather than conforming to a rigid interface. This is rather easier to program to, and easier to read, since you don't have to write empty implementations of listener callbacks that you're not interested in (and yes, I know about listener adapter superclasses).
Here's a sample from the JBossCache docs:
#CacheListener
public class MyListener {
#CacheStarted
#CacheStopped
public void cacheStartStopEvent(Event e) {
switch (e.getType()) {
case Event.Type.CACHE_STARTED:
System.out.println("Cache has started");
break;
case Event.Type.CACHE_STOPPED:
System.out.println("Cache has stopped");
break;
}
}
#NodeCreated
#NodeRemoved
#NodeVisited
#NodeModified
#NodeMoved
public void logNodeEvent(NodeEvent ne) {
log("An event on node " + ne.getFqn() + " has occured");
}
}
The problem with this, is that it's very much more of an involved process writing the framework to support this sort of thing, due to the annotation-reflection nature of it.
So, before I charge off down the road of writing a generic framework, I was hoping someone had done it already. Has anyone come across such a thing?
You can already do this today with EventBus.
Following example is from EventBus Getting Started guide. Statusbar that updates based on published events, and no need to register statusbar control/widget as listener of publisher(s). Without EventBus, statusbar will need to be added as listener to many classes. Statusbar can also be created and destroyed at any time.
public StatusBar extends JLabel {
public StatusBar() {
AnnotationProcessor.process(this);
}
#EventSubscriber(eventClass=StatusEvent.class)
public void updateStatus(StatusEvent statusEvent) {
this.setText(statusEvent.getStatusText();
}
}
A similar project is ELF (Event Listener Framework) but it seems to be less mature.
I'm currently researching about event notification frameworks on Publish-Subscribe Event Driven Programming | Kev's Spring vs Java EE Dev and the followup articles.
I've made http://neoevents.googlecode.com to handle this kind of annotation based event handler.
#actionPerformed
private void onClick() {
//do something
}
protected void initComponents() {
JButton button = new JButton("Click me!!!");
button.addActionListener(new ActionListener(this) );
}
It looks as simple as I was expecting it to be. Annotations are available for every single listener in J2SE.
Don't mistake complicated for clever. It seems to me that this would be:
A nightmare to debug
Difficult to follow (from a maintenance perspective, or someone attempting to change something 6 months down the line)
Full of if (event instanceof NodeCreatedEvent) like code. Why this is better than subclassing an adapter I have no idea!
The main problem I see here are the method parameters, which restrict which methods can actually be used for which events, and there's no compile-time help for that.
This is what makes interfaces attractive to me for observer pattern implementations like the Java event model. Tools like eclipse can autogen method stubs so you can't get the signatures wrong. In your example, it's very easy to use the wrong parameter type and never know it until an event occurs (which might be an error case several months down the line)
One thing you might try are my annotations & processor for implementing observers and null object implementations. Suppose you have
package a.b.c;
public interface SomeListener {
void fee();
void fie();
void fo();
void fum();
}
and wanted to create a listener instance. You could write
package x.y.z;
import a.b.c.SomeListener;
import com.javadude.annotation.Bean;
import com.javadude.annotation.NullObject;
#Bean(nullObjectImplementations = {#NullObject(type = SomeListener.class) })
public class Foo extends FooGen implements SomeListener {
#Override
public void fie() {
// whatever code you need here
}
}
To create a source for these events, you can write
package a.b.c;
import com.javadude.annotation.Bean;
import com.javadude.annotation.Observer;
#Bean(observers = {#Observer(type = SomeListener.class)})
public class Source extends SourceGen {
// SourceGen will have add/remove listener and fire methods
// for each method in SomeListener
}
See http://code.google.com/p/javadude/wiki/Annotations if you're interested. Might give you some other ideas as well.
Google Guava v11 has added an EventBus component that uses this style. They also explain why they decided to use annotations rather than interfaces.
I've been thinking about a generic annotation-driven event framework as well. I like the benefits provided by static typing, but the current interface-driven event model is painful to use (ugly code). Would it be possible to use a custom annotation processor to do some compile-time checking? That might help add some of the missing "safety" that we've all grown used to.
A lot of the error checking can also be done at the time that the listeners are "registered" with the event producers. Thus, the application would fail early (when the listeners are registered), possibly even at at startup-time.
Here's an example of what the generic framework I've been toying with might look like:
public class ExampleProducer {
private EventSupport<ActionEvent> eventSupport;
public ExampleProducer() {
eventSupport = new EventSupport<ActionEvent>(this);
}
#AddListenersFor(ActionEvent.class)
public void addActionListener(Object listener)
{
eventSupport.addListener(listener);
}
#RemoveListenersFor(ActionEvent.class)
public void removeActionListener(Object listener)
{
eventSupport.removeListener(listener);
}
public void buttonClicked() {
eventSupport.fire(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, "Click"));
}
}
The producer uses EventSupport, which uses reflection to invoke the events. As mentioned before, EventSupport could preform some initial checks when the events listeners are registered.
public class ExampleListener
{
private ExampleProducer submitButton;
public ExampleListener()
{
submitButton = new ExampleProducer();
EventSupport.autoRegisterEvents(this);
}
#HandlesEventFor("submitButton")
public void handleSubmitButtonClick(ActionEvent event)
{
//...some code to handle the event here
}
}
Here, EventSupport has a static method that uses reflection to auto-register the listener with the event producer. This eliminates the need to manually register with the event source. A custom annotation processor could be used to validate that the #HandlesEventFor annotation refers to an actual field of the ExampleListener. The annotation processor could do other checks as well, such as ensuring that the event handler method signature matches up with one of the registration methods on the ExampleProducer (basically, the same check that could be performed at registration-time).
What do you think? Is this worth putting some time into fully developing?
Here's a similar project called SJES.
public class SomeController {
private Calculator c1 = new Calculator();
private Calculator c2 = new Calculator();
public SomeController() {
c1.registerReceiver(this);
c2.registerReceiver(this);
c1.add(10, 10);
c2.add(20, 20);
}
#EventReceiver(handleFor="c1")
public void onResultC1(Calculator.Event e) {
System.out.println("Calculator 1 got: " + e.result);
}
#EventReceiver(handleFor="c2")
public void onResultC2(Calculator.Event e) {
System.out.println("Calculator 2 got: " + e.result);
}
#EventReceiver
public void onResultAll(Calculator.Event e) {
System.out.println("Calculator got: " + e.result);
}
}
public class Calculator {
private EventHelper eventHelper = new EventHelper(this);
public class Event {
long result;
public Event(long result) {
this.result = result;
}
}
public class AddEvent extends Event {
public AddEvent(long result) {
super(result);
}
}
public class SubEvent extends Event {
public SubEvent(long result) {
super(result);
}
}
public void unregisterReceiver(Object o) {
eventHelper.unregisterReceiver(o);
}
public void registerReceiver(Object o) {
eventHelper.registerReceiver(o);
}
public void add(long a, long b) {
eventHelper.fireEvent(new AddEvent(a + b));
}
public void sub(long a, long b) {
eventHelper.fireEvent(new SubEvent(a - b));
}
public void pass(long a) {
eventHelper.fireEvent(new Event(a));
}
}
I think this is very easy to use.
You can also check out MBassador It is annotation driven, very light-weight and uses weak references (thus easy to integrate in environments where objects lifecycle management is done by a framework like spring or guice or somethign).
It provides an object filtering mechanism (thus you could subscribe to NodeEvent and attach some filters to restrict message handling to a set of specific types only).
You can also define your own annotations to have customized declaration of your handlers.
And it's very fast and resource efficient. Check out this benchmark showing a performance graph for different scenarios using Guava or mbassador.