Question

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
Was it helpful?

Solution 3

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.

OTHER TIPS

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));
  }
}

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);

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?

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.

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?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top