3

Update: I am about to add a bounty to this question. I added the entire project's source code to GitHub here:

https://github.com/doctrang/gwt-activities-places-mvp-example

I decided to rename my SimpleModule to WebModule; so, whereas in all my code snippets below, the GWT module is named SimpleModule or simplemodule, in my latest code you will see the module named WebModule and webmodule respectively - but they are 1 in the same!

Note: I understand I might not have things set up perfectly here, and might have some dead code (SimpleModule.css, etc.) that isn't being used at all, but this is my very first GWT app and I just want to get the thing up and running!

I am experimenting with my first GWT app (2.5.1) and am trying to get a svery simple UI to display using the recommended Places & Activities framework (for history management) as well as utilizing a basic MVP architecture.

For simplicity's sake, I have placed all the Java code inside my SimpleModule.java (entry point). Once I get this proof-of-concept working, I'll decompose SimpleModule.java into more classes.

My goal is to have the GWT app load when the user goes to my home page (me.example.com). Because of this, I create a SimpleModule implements EntryPoint, and then renamed the host page from SimpleModule.html to index.html (so that when users go to me.example.com or me.example.com/index.html, they will pull down the SimpleModule).

My WAR's directory structure:

war/
    hosts/
        simplemodule/
            SimpleModule.css
    WEB-INF/
        classes/
        lib/
        deploy/
        web.xml
    simplemodule/
        css/
        font/
        gwt/
        img/
        js/
        prettify/
        clear.cache.gif
        hosted.html
        simplemodule.nocache.js
    img/
        mylogo.jpg
    index.html

And index.html:

<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <script type="text/javascript" language="javascript" src="simplemodule/simplemodule.nocache.js"></script>
    </head>
    <body>
        <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
        <noscript>
            <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
                Your web browser must have JavaScript enabled in order for this application to display correctly.
            </div>
        </noscript>
    </body>
</html>

And web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
    <servlet>
        <servlet-name>greetServlet</servlet-name>
        <servlet-class>com.myapp.server.GreetingServiceImpl</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>greetServlet</servlet-name>
        <url-pattern>/simplemodule/greet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>remoteLogging</servlet-name>
        <servlet-class>com.google.gwt.logging.server.RemoteLoggingServiceImpl</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>remoteLogging</servlet-name>
        <url-pattern>/simplemodule/remote_logging</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

And SimpleModule.java:

public class SimpleModule implements EntryPoint {
    private EventBus eventBus = new SimpleEventBus();
    private PlaceController placeController = new PlaceController(eventBus);
    private PlaceHistoryMapper placeHistoryMapper;
    private PlaceHistoryHandler placeHistoryHandler;
    private Place defaultPlace;
    private ActivityMapper activityMapper;
    private ActivityManager activityManager;
    private LoginDisplay loginDisplay = new LoginDisplay();

    @Override
    public void onModuleLoad() {
        bootstrap();

        RootPanel.get().add(loginDisplay);
        activityManager.setDisplay(loginDisplay);

        placeHistoryHandler.register(placeController, eventBus, defaultPlace);
        placeHistoryHandler.handleCurrentHistory();
    }

    private void bootstrap() {
        placeHistoryMapper = new PlaceHistoryMapper() {
            @Override
            public String getToken(Place arg0) {
                return "home";
            }

            @Override
            public Place getPlace(String arg0) {
                return defaultPlace;
            }
        };

        placeHistoryHandler = new PlaceHistoryHandler(placeHistoryMapper);

        defaultPlace = new Place() {};

        activityMapper = new ActivityMapper() {
            @Override
            public Activity getActivity(Place arg0) {
                return new LoginActivity();
            }
        };

        activityManager = new ActivityManager(activityMapper, eventBus);
    }

    public class LoginDisplay extends SimplePanel {
        private LoginDisplayUiBinder uiBinder = GWT
            .create(LoginDisplayUiBinder.class);

        public LoginDisplay() {
            super();

            uiBinder.createAndBindUi(this);
        }
    }

    public interface LoginDisplayUiBinder extends UiBinder<Widget, LoginDisplay> {
        // ???
    }

    public class LoginActivity extends AbstractActivity {
        @Override
        public void start(AcceptsOneWidget panel,
                com.google.gwt.event.shared.EventBus eventBus) {
            panel.setWidget(loginDisplay);
        }
    }
}

And LoginDisplay.ui.xml:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
        xmlns:g="urn:import:com.google.gwt.user.client.ui"
        xmlns:b="urn:import:com.github.gwtbootstrap.client.ui">
    <g:HTMLPanel>
        <img src="img/mylogo.jpg" />

        <hr/>

        <form action="doStuff" method="post" class="form-horizontal"
                id="someForm" accept-charset="utf-8">   
            <div class="control-group">
                <label for="username" class="control-label">    
                    Username:
                </label>
                <div class="controls">
                    <input name="username" type="text" value="" id="username"/>
                </div>
            </div>
            <div class="control-group">
                <label for="password" class="control-label">    
                    Password:
                </label>
                <div class="controls">
                    <input name="password" type="password" value="" id="password"/>
                </div>
            </div>
            <div class="control-group">
                <div class="controls">
                    <input type="button" class="btn-danger" value="Login"/>
                </div>
            </div>
        </form>     
    </g:HTMLPanel>
</ui:UiBinder>

Update: and SimpleModule.gwt.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN"
        "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd">
<module rename-to='simplemodule'>
    <inherits name='com.google.gwt.user.User'/>

    <!-- Configure logging. -->
    <inherits name="com.google.gwt.logging.Logging"/>
    <set-property name="gwt.logging.logLevel" value="FINEST"/>
    <set-property name="gwt.logging.enabled" value="TRUE"/>
    <set-property name="gwt.logging.consoleHandler" value="ENABLED"/>
    <set-property name="gwt.logging.developmentModeHandler" value="DISABLED" />
    <set-property name="gwt.logging.popupHandler" value="DISABLED" />
    <set-property name="gwt.logging.systemHandler" value="DISABLED" />
    <set-property name="gwt.logging.firebugHandler" value="DISABLED" />
    <set-property name="gwt.logging.simpleRemoteHandler" value="DISABLED" />

    <!-- GWT-Bootstrap. -->
    <inherits name ="com.github.gwtbootstrap.Bootstrap"/>

    <inherits name='com.google.gwt.user.theme.clean.Clean'/>

    <entry-point class='com.myapp.client.SimpleModule'/>

    <source path='client'/>
    <source path='shared'/>
</module>

Web page source after server startup:

<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <script type="text/javascript" language="javascript" src="simplemodule/simplemodule.nocache.js"></script>
    </head>

    <body height="100%" width="100%">
        <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
        <noscript>
            <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
                Your web browser must have JavaScript enabled in order for this application to display correctly.
            </div>
        </noscript>
    </body>
</html>

When I run this in Dev Mode (Ant target that invokes Java on com.google.gwt.dev.DevMode), I get the DevMode tool launching without errors. When I select "Launch Application", I get a blank web page. When I open Firebug and prod around for errors, I don't see any.

What is wrong with my setup??? Why am I not seeing a simple image logo with login fields underneath it? Thanks in advance!

Edit: My latest update. I followed @Raphael's suggestions (inheriting the Place and Activity modules, and adding the @UITemplate annotation to LoginDisplayUiBinder), I get the label "Hello, GWT!" printing to my browser!!! I then modified my onModuleLoader() method to look like:

@Override
public void onModuleLoad() {
    bootstrap();

    //      RootPanel.get().add(new Label("Hello, GWT!"));
    RootPanel.get().add(loginDisplay);
    activityManager.setDisplay(loginDisplay);

    // Connect the PlaceController to the EventBus, and set the
    // defaultPlace as our first place in history.
    placeHistoryHandler.register(placeController, eventBus, defaultPlace);
    placeHistoryHandler.handleCurrentHistory();
}

And am now getting the following exception:

onModuleLoad() threw an exception
Exception while loading module com.dummylandapp.client.WebModule. See Development Mode for details.
    java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:406)
    at com.google.gwt.dev.shell.OophmSessionHandler.loadModule(OophmSessionHandler.java:200)
    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:526)
    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)
    at java.lang.Thread.run(Thread.java:679) Caused by: com.google.web.bindery.event.shared.UmbrellaException: Exception caught: Exception caught: (HierarchyRequestError) @com.google.gwt.dom.client.Node::appendChild(Lcom/google/gwt/dom/client/Node;)([JavaScript object(15)]): Node cannot be inserted
    at the specified point in the hierarchy
    at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:203)
    at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
    at com.google.gwt.place.shared.PlaceController.goTo(PlaceController.java:156)
    at com.google.gwt.place.shared.PlaceHistoryHandler.handleHistoryToken(PlaceHistoryHandler.java:192)
    at com.google.gwt.place.shared.PlaceHistoryHandler.handleCurrentHistory(PlaceHistoryHandler.java:118)
    at com.dummylandapp.client.WebModule.onModuleLoad(WebModule.java:66) ... 9 more Caused by: com.google.gwt.event.shared.UmbrellaException: Exception caught: (HierarchyRequestError) @com.google.gwt.dom.client.Node::appendChild(Lcom/google/gwt/dom/client/Node;)([JavaScript object(15)]): Node cannot be inserted
    at the specified point in the hierarchy
    at com.google.gwt.activity.shared.ActivityManager.onPlaceChange(ActivityManager.java:168)
    at com.google.gwt.place.shared.PlaceChangeEvent.dispatch(PlaceChangeEvent.java:70)
    at com.google.gwt.place.shared.PlaceChangeEvent.dispatch(PlaceChangeEvent.java:1)
    at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
    at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
    at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193) ... 14 more
  • 1
    This is probably a problem with width, height etc. Try to put width and height at 100% for ``, `` and your main `
    `. With chrome, you can also introspect your app with `F12` to check the size of your components.
    – Arnaud Denoyelle Jun 26 '13 at 13:28
  • Thanks @adenoyelle (+1) - to set width/height to 100%, where would I put that? I am actually using `gwt-bootstrap` (a GWT port for Twitter Bootstrap) and all of their CSS files... –  Jun 26 '13 at 13:43
  • As it is only to test if the problems comes from here, you can test it directly with firebug. – Arnaud Denoyelle Jun 26 '13 at 13:45
  • 4
    It is very difficult to help when you share a 192 MB project in github. You should share just the bare necessary project and not entire files from temp,build,etc !!!!! I just wasted 5 minutes of time and bandwidth before realizing the size of the download and then cancelled the download!!!! – appbootup Jul 04 '13 at 04:06
  • Thanks @SSR (+1) - I'm new to git and GitHub altogether; I figured it was the best way to quickly get my project's code up to a public repo, but stumbling around with it, ended up deciding to just upload everything instead of trying to force Git to cherry pick which files to upload and which ones not to (like lib, bin, etc.). Hopefully the 500pt bounty makes the added effort somewhat worthwhile. –  Jul 04 '13 at 05:15
  • 1
    This question needs a good edit. You've got a lot of code samples there, yet you also link to your entire project. And finally, you seem to change question half-way down the page and seek help with an exception. – Duncan Jones Jul 09 '13 at 09:35

6 Answers6

3

Problem is here :

public class LoginDisplay extends SimplePanel {
    private LoginDisplayUiBinder uiBinder = GWT
        .create(LoginDisplayUiBinder.class);

    public LoginDisplay() {
        super();

        uiBinder.createAndBindUi(this);
    }
}

You create your widget but never add it to the panel:

uiBinder.createAndBindUi(this);

Try :

this.add(uiBinder.createAndBindUi(this));

Note that you can also put the uiBinder interface in LoginDisplay class as it is only needed here (makes your code clearer) :

public class LoginDisplay extends SimplePanel {

  public interface LoginDisplayUiBinder extends UiBinder<Widget, LoginDisplay> {}

  public LoginDisplay() {
    super();

    LoginDisplayUiBinder uiBinder=GWT.create(LoginDisplayUiBinder.class);
    this.add(uiBinder.createAndBindUi(this));
  }
}
Arnaud Denoyelle
  • 29,980
  • 16
  • 92
  • 148
  • Thanks - good catch @adenoyelle (+1) - however I'm still getting a blank web page and Firebug isn't reporting any errors... –  Jun 26 '13 at 13:37
  • With Firebug, do you see the form elements in the DOM? – Arnaud Denoyelle Jun 26 '13 at 13:42
  • No, I don't see them. Also, there is an element called `simplemodule` that has a value of `null`. –  Jun 26 '13 at 13:46
  • 1
    What happens if you remove all the lines of `onModuleLoad()` and keep only the line `RootPanel.get().add(loginDisplay);`? – Arnaud Denoyelle Jun 26 '13 at 13:49
  • Still no changes, @adenoyelle. I'll try to add your CSS suggestion to set height & width of the to 100% and will report back. –  Jun 26 '13 at 14:01
  • Sometimes, the GWT app takes time to appear in dev mode. Did you try to just wait 30s? You can also try to reduce `onModuleLoad()` to this simple line : `RootPanel.get().add(new Label("Hello, world!"));`. If this still does not work, can you copy paste the URL you are targetting? – Arnaud Denoyelle Jun 26 '13 at 14:08
  • Ok, I in `index.html` I changed `` to ``, and I also replaced `RootPanel.get().add(loginDisplay)` with `RootPanel.get().add(new Label("Hello, GWT!"));`. I also waited 3 minutes to see if anything displayed. Nothing changed, same blank screen without errors. Like I said, I'm developing locally with `devmode`, so the URL is: `http://127.0.0.1:8888/index.html?gwt.codesvr=127.0.0.1:9997`. I do have a public test site that I can deploy to if you need/like. –  Jun 26 '13 at 14:16
2

You are using Place and Activity in your project but your module does not inherit them. Add the following lines to WebModule.xml :

<inherits name='com.google.gwt.place.Place'/>
<inherits name='com.google.gwt.activity.Activity'/>

Also, you have to add the UiTemplate annotation to your UiBinder interface if the view template has not the same name as its enclosing class. In your case, GWT is looking for WebModule.ui.xml when trying to create a LoginDisplayUiBinder.

@UiTemplate("LoginDisplay.ui.xml")
public interface LoginDisplayUiBinder extends UiBinder<Widget, LoginDisplay> {}

Update

Your new exception is caused by this:

RootPanel.get().add(loginDisplay);
activityManager.setDisplay(loginDisplay);

You add the login form a first time and set it as the main display for your ActivityManager. The display is the panel argument given to your activities in their start method :

void start(AcceptsOneWidget panel, com.google.gwt.event.shared.EventBus eventBus);

In your case, when you trigger a page change event (by using placeHistoryHandler.handleCurrentHistory();), LoginActivity will try to add LoginDisplay to itself causing the Exception :

panel.setWidget(loginDisplay);

A simple fix you can do is to create an other SimplePanel and set it as the main display:

final SimplePanel mainPanel = new SimplePanel();
RootPanel.get().add(mainPanel);
activityManager.setDisplay(mainPanel);
Raphaël
  • 3,646
  • 27
  • 28
  • Thanks @Raphael (+1) - I'll try it out and report back with what I find! –  Jul 08 '13 at 20:27
  • Waa waa wee wah!!! Thanks @Raphael, sooo close, we're almost there! I implemented both your suggested changes (inheriting the Place and Activity modules in my `WebModule.gwt.xml` as well as adding the `@UiTemplate` annotation), and got the "Hello, GWT!" label printing to my screen. Please see my latest edit for what is currently happening. Help me get my `loginDisplay` drawing to the screen and the bounty is all yours! Thanks again! –  Jul 08 '13 at 21:25
  • Also, additionally, just curious here: I'm shocked that I never got an error message, or even a warning, when I was not inheriting the Place/Activity modules!!! Is this typical of GWT, or is there a log of some sort that I could have consulted to diagnose this myself? –  Jul 08 '13 at 21:27
  • 1
    @TicketMonster I used Maven (+ Netbeans) to build your project and got some errors during compilation. I don't know why they did not show up for you :/ – Raphaël Jul 08 '13 at 21:57
  • Thanks @Raphael that worked! Last followup question, I promise: I'm still not fully understanding your fix with adding the SimplePanel to RootPanel, and then again with the activityManager. Is it that the SimpePanel can then act as a container for the AcceptsOneWidget that gets sent to the LoginActivity#start method? –  Jul 09 '13 at 01:07
  • @TicketMonster `SimplePanel` implements `AcceptsOneWidget`. The instance of `AcceptsOneWidget` you set as display is the same that will be given when `start(...)` is called (well actually a Wrapper is used by GWT). If you don't add the display to the `RootPanel`, nothing will show up. – Raphaël Jul 09 '13 at 08:11
0

Do you have yourapp.gwt.xml file? If so, please post it. If not, thats the reason. More about it at GWT documentation. Because it looks like you might be lacking <entry-point class='com.myapp.MyEntryPointClass' />

Because this will load your application without any problems, launch your html file, however no code will get executed, leaving you with not modified html file you provide.

How do you build this app?

Kaszaq
  • 997
  • 10
  • 16
  • Thanks @Kaszaq (+1), to answer your questions: yes I do have a `SimpleModule.gwt.xml` written and have updated my original post with its contents. It is packaged under `com.myapp` whereas `SimpleModule.java` is packaged under `com.myapp.client`. As to how I build my app, I used webAppCreator to produce my initial project directory structure, which included a `build.xml` file with a `devmode` target. This is the target that populates my `war/` directory with all the files it needs, and launches the DevMode tool. –  Jun 26 '13 at 15:38
  • @TicketMonster - you have '' so your js files should not be simplemodule.nocache.js as you wrote, but webmodule/webmodule.nocache.js. Can you confirm that after you build the name of your javascript files [.nocache.js] are prefixed with simplemodule rather than webmodule? – Kaszaq Jun 26 '13 at 16:21
  • Sorry that is a cut n' paste error - updating the original post to reflect the correct value. –  Jun 26 '13 at 16:28
  • @TicketMonster - please paste also the webpage sources of the webpage you see after starting the server. – Kaszaq Jun 27 '13 at 13:57
0

I always run my apps with the same name of project, the same Module name, and the same Html page.

Like this:

Project: SimpleModule

XML: SimpleModule.gwt.xml

Containing this:

Finally

SimpleModule.html

You dont need to rename it as index.html.

When gwt compiles, lets say you are running it in a tomcat, it doesnt need an index.html, it recognizes the SimpleModule.html as the index.

Hope it help.

You should put your log error so to be more clear and i recommend to srart a new project. See how it works, and analyze whats missing in yours.

Dont forget de web.xml also.

Fabrizio Guespe
  • 583
  • 1
  • 10
  • 25
  • Thanks @fguespe (+1) - a few followups: (1) is this just a hypothesis of yours (that renaming `WebModule.html` to `index.html` is the root cause)? Or are you certain? (2) Before I renamed it `index.html`, when I deployed it to Tomcat locally, simply going to `localhost:8080/dummylandapp` did not cause my module to download. Instead, I had to go to `localhost:8080/webmodule/WebModule.html`. This conflicts with your statement that "*...it recognizes the SimpleModule.html as the index*" - thoughts? And (3) just FYI - I *did* provide the web.xml - both in my code snippets and on the GitHub repo. –  Jul 04 '13 at 00:31
  • Thanks again for any input/feedback! Once I get answers to these followups I will try your suggestions out and report back with what I find! –  Jul 04 '13 at 00:32
0

1) Are you using Eclipse for this or some other IDE? When I tried using a different IDE (so no plugin) with ANT files, I couldn't get GWT to work properly.

2) You left the whole GreetingService servlet in there, are you sure that's not causing you some troubles?

Marconius
  • 683
  • 1
  • 5
  • 13
  • Thanks @Marconius (+1)! 1) I am using Eclipse, but **not** using the Google-Eclipse plugin. I used the `webAppCreator` tool that ships with the GWT SDK to create the initial project (hence the `GreetingService` servlet and other dummy code) and then imported it into Eclipse from my file system. **Please note** that this worked perfectly fine when I first imported the code into Eclipse. So all the Places/Activities/MVP stuff I added has broken it somehow. And (2) The `GreetingService` servlet *might* be causing some issues, but again, this worked perfectly fine until I started added my changes. –  Jul 06 '13 at 17:30
  • To see how the module was working *before* I added my changes, in `WebModule.java`, comment-out the entire top portion of the `onLoad()` method. Then un-comment the lower portion that starts with "*EVERYTHING AFTER THIS POINT WAS THE ORIGINAL WebModule.java AND WAS WORKING AS OF 6/25/2013.*". This will get the app working fine, and is the code that was autogenerated for me by `webAppCreator`. –  Jul 06 '13 at 17:32
  • Yes, the ant script generated with the app creator works for the example app, obviously. But when I tried using that for a program I wrote (also based on the example app), I found that after a point, it refused to compile. Since I don't know the first thing about ant, I had no idea how to fix the issue; my solution was to simply use the Eclipse plugin. – Marconius Jul 07 '13 at 00:54
  • This feels more like a comment than an answer. I've flagged for deletion. – Duncan Jones Jul 09 '13 at 09:04
0

Activities & Places is a noble concept that will never take off because of its inherent complexity. Try gwtp (GWT Platform) out instead. You'll never go back. You can have working MVP examples up-and-running in minutes, and GWTP has all the history management/bookmarking that A&P have with a much easier API to understand and code against.

Trust me, GWTP is the way to go for all MVP apps.

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756