1

This morning I asked this question and received a really great answer for it. I'm now trying to prototype the design and am running into a similar (but not same) issue. Essentially I'm trying to have a 100% configuration-driven GWT UI, where changes to a DB can produce radically different UIs but without any code changes.

My architecture is simple:

  • I will use a separate tool (or at first, by hand) to produce a .xul (XUL) file and save it to a database; probably a document database like Mongo or something similar
  • On the server-side, I will write a XulParser that reads the XUL file out of the database and turns it into a ContainerProxy instance
    • A ContainerProxy is my "proxy" equivalent to a com.google.gwt.user.client.ui.Panel or something similar; it is just a bean/POJO that contains a list of other widget proxies (see code snippet below)
    • For instance, I might have a XUL file that defines a Button like the one below
    • This ButtonProxy would be added to a ContainerProxy (along with any other UI widgets in the same container/view/panel)
  • On the client-side, I'll query for the ContainerProxy somehow (???), and pull it down from the server.
  • I'll then have a mechanism that translates each of the ContainerProxy's children (the ButtonProxy, etc.) into actual UI widgets.

This way, at first I can put a certain XUL file into the database and the UI might only contain the "Order Now" button on it. But down the road, I might want to use a totally different UI, so I design a different XUL file, update the document in the database, and - voila - the UI changes for all users without any code changes. Please note: I understand this is not a normal way of doing things: I have a special use case where I need such config-driven UIs.

To help clarify the XUL-parsing process:

<button id="order" label="orderNow" clickHandler="org.myapp.OrderButtonHandler" />

after the XulParser reads the above snippet, we get:

ButtonProxy orderButton = new ButtonProxy("order", "OrderNow");
orderButton.addClickHandler(new OrderButtonHandler());

Anyways, my questions:

  1. What do I need to do on the client-side to query for my ContainerProxy? Can anyone provide pseudo-code to help me visualize it?
  2. Once I have the ContainerProxy on the client-side, what UI mechanisms are available for me to translate the proxied classes into actual UI widgets? Is UIBinder available? Again, can someone provide some pseudo-code?

Thanks in advance for any help here!

Community
  • 1
  • 1
IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • 1
    Instead of xul why don't you write the code you store in the database as html fragments. That way you don't need any translation. You can then inject the html fragment into the DOM then query the DOM to find any elements you want to wire up to handlers you have written. Of course using GWT to do this you will need to have all you handlers written before hand (you can create new buttons with new functionality on the fly) – Deanna May 11 '13 at 16:04
  • 1
    Typo in above comment, You CAN"T create new functionality on the fly. In other words, you can't add GWT compiled code on the fly. But you can inject new javascript handlers on the fly if you need that. – Deanna May 11 '13 at 16:13
  • Thanks @Deanna (+2 for both) - yeah I guess in hindsight there's no advantage of XUL and I could just store HTML snippet directly. But I'm still learning the ropes with GWT and am having a tough time visualizing the solution you're suggesting here. Any chance you could add an answer with a code example, or even just pseudo-code? Might help some lightbulbs go off. Thanks again for all the help so far! – IAmYourFaja May 12 '13 at 01:53

1 Answers1

1

Here is a bit of a code idea that would do what you wanted. I haven't tested this, but you can get the idea of how it all could work together from it.

    String htmlFragment = "<div><button id='action1' type='button>Action 1<button/><div/>";

    HTMLPanel container = new HTMLPanel(htmlFragment);

    RootLayoutPanel.get().add(container);

    Element button1El = container.getElementById("action1");

    if(button1El != null){
        Button button1 = Button.wrap(button1El);
        button1.addClickHandler(new ClickHandler(){

            @Override
            public void onClick(ClickEvent event) {
                // What you want button 1 to do
            }

        });
    }
Deanna
  • 696
  • 1
  • 5
  • 15
  • Thanks @Deanna (+1) - I'm *starting* to see it come together, but still one problem. In your simple/conceptual example the `htmlFragment` is a String. In reality, I need to read it out of a DB and pull it down on the client-side. That way, one day, `htmlFragment` could be a `
    ` containing a ``, and another day, it might contain an entire `
    ` or panel of other widgets. **This is the root of my confusion**: how do I (from the client-side) pull down widgets (that are stored on a database as XML/HTML/XUL/etc.) from the server-side and present them to the end user? Thanks again!
    – IAmYourFaja May 12 '13 at 12:11
  • 1
    To access the database you need to use requestFactory. You will need server side code. I don't know which database you are using, so lets say you just write a service that returns the string with the fragment from the database. You then write a requestFactory proxy for the service (which is called a context and is just an interface). This code goes in the shared folder. The context is put inside a requestfactory interface... – Deanna May 12 '13 at 13:01
  • 1
    Then on the client side you GWT.create the requestFactory. From that you get the context. Then you fire the request to the service method to get the string. In the onSuccess handler for that you use the above code. RequestFactory is great but the docs for it are a little terse. There are lots of blog posts with examples on using it though. Just search for request factory example. – Deanna May 12 '13 at 13:04
  • Thanks again @Deanna (+1) - I wish I could upvote your answer(s) more. One last, final followup (I promise). I asked a similar-but-different question last week, and the person who gave me an answer (and who originally pointed me in the direction of XUL) was talking about having to write a lot of if-else conditionals on the client-side. Would you mind, if you get a chance, to just skim over his answer and help me make sense of it? I only ask because your solution here doesn't seem at all what he recommended and I'm wondering if I'm way out to lunch and not asking the right question... – IAmYourFaja May 12 '13 at 13:57
  • [Here is the link](http://stackoverflow.com/questions/16481138/is-configuration-driven-gwt-ui-possible) and it's also above in the opening sentence to this question - thanks again for any and all help! – IAmYourFaja May 12 '13 at 13:58
  • What server technologies are you going to use. Java servlets is required if you use request factory, but you didn't mention what db technology stack you are using. For example if you run this on appengine you could choose datanucleus and jpa (or jpo). If you run it else where you may use eclipse-link and mysql or any other db tech. There a lot of choices you can make that go between your service and the db and there all have their uses. For RequestFactory (the way to get data from the service to the client) go to https://developers.google.com/web-toolkit/doc/latest/DevGuideRequestFactory – Deanna May 12 '13 at 14:51
  • Haven't decided yet @Deanna - most likely a PaaS like Elastic Beanstalk/Dynamo, or GAE/BigTable. Plan on using RF and servlets for data service calls. I guess I'm just thrown off by his statement "*Lack of support for reflection in GWT means, that you'll have to handle tags by if/switch statements, and yes, that makes that code even bigger.*", whereas in your code snippet, I don't see anything that remotely resembles that (if/else/switch). And being new to GWT, that throws up caution flags, and I hope I haven't asked a completely different question that I *thought* was similar! Thanks again! – IAmYourFaja May 12 '13 at 14:56
  • I haven't ran into a case where I needed reflection on the client side. I am not sure where that quote if from, but what type of tags was it referencing? There isn't anything about the use case that you asked about that needs reflection that I can see. – Deanna May 12 '13 at 15:02
  • Oh, never mind. I found the quote in your other post. That was dealing with parsing XUL by hand on the client which you don't need to do. And even then I don't see where you need reflection if you did do it. But you really don't want to do that. That is totally unnecessary code where you can use html fragments directly. – Deanna May 12 '13 at 15:04