GWT+Java: Globals, Singletons, and Headaches
So here's my project:
I am building a central interface/dashboard to present the test data for several test types of multiple product versions. We're using TestNG on our massive product, and while not enough tests are being written, that's a discussion for another topic. Here's what the directory structure looks like:
Filesystem/productVersion+testType/uniqueDateAndBuildID/testng-results.xml
That results.xml file contains tags with child test tags, which correspond to a filesystem directory and then xml files containing actual test case results (pass, fail, etc) The XML parsing and filesystem traversal is all well and good/reliable.
Flow of control: Client accesses main page --> server opens properties file --> server checks for web server property (either Websphere or Tomcat, if I'm working locally) --> server sets bunch of constants based on that. Constants include: root filesystem directory, filesystem separator (translation), "like types (basically same tests on different platforms)", and a base URL to append onto. --> server then reads properties file some more and does all of its XML processing. Results are cached in memory as well as to the filesystem using ObjectOutputStream. --> A big list of results is sent back to the client to do the UI processing/display.
Here's where I run into a problem: I can't access those Global variables (contained/set in a Globals class...bad I know :-/ ) back on the client, even though they're in the shared folder. If you're wondering why I can't just load the properties again, it's because the client is GWT-ified Javascript which doesn't include File(). So my next thought, having done a little bit of upper level Java reading was to maybe use a Globals singleton object and pass that back too..but it seems like that's just as bad if not impossible. Suggestions here would be great.
This whole thing is pretty tightly coupled, something my previous Java education hadn't really gotten into yet. And since this is just an internal portal for devs to check, there doesn't seem to be much of a point in actually testing my code. As long as it displays correctly, logs properly, and handles errors gracefully, right? All in all it's <15 classes, so it's not really a big big deal I guess. Should I refactor to clean it all up and make it "better Java", comment everything to clearly delineate flow of control, or not worry too much about it because it's small? I know in the future to think more about things before I design them, but I really didn't know a large amount of the higher Java principles I've been exposed to since starting.
edit after do开发者_如何学Cing a bit of thinking, came up with a possible workaround. What about, instead of passing back only a list of results, I passed back some other custom list implementation that included a globals 'header' object? I could preserve state.
A simple solution would be the Dictionary
class:
Provides dynamic string lookup of key/value string pairs defined in a module's host HTML page. Each unique instance of Dictionary is bound to a named JavaScript object that resides in the global namespace of the host page's window object. The bound JavaScript object is used directly as an associative array.
You just need to add some dynamic content to your host HTML page - make the server print the values read from the properties file in the form of a JavaScript object:
var GlobalProperties = {
property1: "value1",
property2: "value2"
};
Then, use Dictionary in your code to read those values:
Dictionary globalProperties = Dictionary.getDictionary("GlobalProperties");
String property1 = globalProperties.get("property1");
PS: If you are looking for good ideas/advices on how to make your code less coupled -> more testable, I'd recommend Misko Hevery's blog. He's got many interesting posts, like why singletons are usually bad (global state, not the pattern itself). But most importantly - it has the awesome guide to writing testable code (some guidelines used internally in Google).
You could pass those Global variables using a simple object with a HashMap thought a GWT-RPC call or just include this Hashmap with the result you already retrieve in the first place (along the "big list of results [that] is sent back to the client to do the UI processing/display.")
You can't access serverside singletons from the compiled javascript.
You have two options basically. You can make a Serializable
class in the client code, that represents the global variables, or pass your global variables object, but this is a rather inefficient solution.
The simplest is to use a HashMap<String, String>
in a serializable object, which you can retrieve with an RPC call:
public class GwtGlobalVariables implements Serializable {
private HashMap<String, String> map = new HashMap<String, String>();
public void put(// a delegate put method of choice
public void setMap() // a getter / setter for the map if you need it
}
Ensure the class is within a GWT module's source folders, i.e. in the same place as your entry point maybe.
Fill the map out with the values needed, pass it through rpc and you have it in your client side code.
精彩评论