I'm not sure if this is the right forum for this, so if I am mistaken I apologize.
I'm working on a project that has two separate components. The first is a back end, that will do most of the heavy lifting, the other part is a front end GUI. The GUI will include the back end into it's project as an imported JAR file.
I need to be able to keep these two decoupled, as I might be writing different front ends using the same back end. The challenge in front of me (well one of many) is how to pass messages from the back end to the GUI so I can report things that are happening.
For example, if i call method FOO, FOO might do several different things; connect to a database, divide by zero, solve world hunger. I want to be able to either tie a JTextArea , or another component (or multiple components) to this stack of information, or at the very least, have something listening for this information, and when I see that my back end reports something, my front end is quickly aware of this information, and then I can process it and inform the user of the front end.
It would also be useful to be able to send a message from front end to back end , so perhaps the back end might learn that the front end user is unhappy and would like to stop running the current query.
I've done some of the basic Googling as is customary, but I haven't found anything that jumps out at me that says this is the best idea. JMS queues seem a bit overkill, and not sure about sockets and listeners or anything there. Any direction I take will be new and exciting, right now I'm just looking for input on what folks think. Any thoughts?
Front to back is easy. You provide your model with a method that performs a certain action, and then the controller at the front simply calls that method.
Back to front you can do with a listener pattern. Create some sort of listener interface, and have your view implement it. Register it with the model, and when the model updates itself, fire events that the listeners can respond to.
The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.
First off thank you for answering my question, but I'm still very confused (more from my ignorance then what I'm sure is an awesome explanation).
So I have spent the last couple days separating my front end and back end (not a trivial endeavor!). I now have three projects in Eclipse: GUI, CORE, and TOOLS. Both GUI and CORE import TOOLS, which contains for the most part shared classes. My CORE project now works fine on it's own (the product was command line first and still supports that) now that I have pulled it out. GUI also imports CORE, and I expect to be able to call methods and create classes that exist in the Core.
The two things I need to accomplish in quite a few places and that I'm still having a hard time understanding:
1) I've just done something (say query a database and got my results) in the CORE. I now want to tell the GUI user (via JTextArea) that I have completed that query and I'm moving onto the next step. Previously I would just Append to that TextArea since my Core and my GUI were tied together. Now my core has no knowledge of the GUI, so I just need to put that message somewhere. I am assuming that I can attach a Listener to my Jtext area to listen for these changes, and if I find these changes update itself, but i wasn't putting anything anywhere before. Do I just create a LoggerClass maybe and instead of writing to the text area, write to a String in this logger class, and the JText area listens for changes to a String in this class? I know I'm probably getting bogged down in the details here, but it's still confusing to me.
2) When I complete a task, say I've made one iteration of a loop, I need to update an objects counter for example. Lets call this custom object MyData. My data has a counter which I increase by X. When I increase this counter I want to update a row/column of a jtable that we are currently working with, as well as update my progress bar. I'm assuming that I can attach a listener to the JTable to listen for changes in myData, so when i say myData.addSuccess(1), that my JTable will "hear" this and know it needs to change it's value to myData.currentSuccessCount() and also go ahead and update the Progress bar.
This was all much easier when they were coupled. I'm sorry I don't quite get it, but any additional thoughts would be helpful. And if Not, I'm sure I'll eventually figure it out and I appricate your time regardless.
A common way of implementing GUI applications is via the MVC pattern. That's Model, View, Controller. Clearly your GUI is the View part, and it should be pretty clear that your database access code belongs to the Model part. And the purpose of the Controller part is to be in charge. It mediates between the other two parts. So in your example, the Controller would ask the Model to get some data from the database, and then it would tell the View to update itself with the result of that query.
However that's easy to say and not so easy to do. It's possible to have the Controller do nothing more than set up listeners whereby the View can react to Model events and the Model can react to View events, or you can have a more big-government Controller which knows everything that's going to happen in the system and takes full control of all of it. At any rate, either option requires you decide on the architecture and then to analyze your application to see what are the events, who should handle them, and how. It's a surprisingly (and annoyingly) detailed process. In your application, for example, the act of clicking on a "Run" button might be an event which causes the database code to run on another thread. Then the completion of that database code might be one event, and a progress report from the database code might be another event, which cause something to happen in the View.
The other thing to notice about these events is that they may or may not correspond to events which normally occur in Swing components. The button-click event does, but the database processing events don't. So you can't expect to use standard Swing events and you might have to write your own. The tools to do this are java.awt.EventObject and java.awt.EventListener at the lowest level, and PropertyChangeEvent and PropertyChangeListener for code with some built-in behaviour which is useful in some cases. The Oracle tutorial is here: Lesson: Writing Event Listeners but be warned that it's more Swing-centric than what you actually need.
Whenever you find yourself dealing with the problem: "I want A to tell B something happened, but A is not supposed to know about B's existence", the answer is to allow B to listen to changes to A. How do you set up A so that other things can listen to it? Create a listener interface in A's module (CORE in your case) that can register with A. B can pass a concrete implementation of the interface to A, because they both know of the interface's existence.
Let's say you have a module called Core.jar. Core.jar contains a class that periodically makes weather readings, and saves them to a database. Let's call it Weather. Now, you have a separate module, View.jar, that contains a class WeatherReport. WeatherReport contains a JFrame with a JTable that lists various data about the current weather. WeatherReport knows of the existence of Weather, but Weather doesn't know about WeatherReport. So how are you going to give WeatherReport updated state of affairs, without harrassing Weather constantly for it's current state?
Enter WeatherListener. WeatherListener is a class that is part of Core.jar. WeatherReport has a helper that implements WeatherListener, and registers it with Weather. Whenever Weather makes a new reading, it tells all its listeners that a weather update occurred. It just told WeatherReport it had new readings, without knowing of WeatherReport's existence!
Like Paul said, this follows the MVC design. Weather, WeatherReading and WeatherListener form your model. WeatherReport represents the view and the controller parts.
Joined: Oct 05, 2007
This helped out a TON. I'm not completely there yet, but great example. Than you so much everybody!