com.google.gwt.gears.sample.workerpool.client.WorkerPoolDemo.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.gears.sample.workerpool.client.WorkerPoolDemo.java

Source

/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.gears.sample.workerpool.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.gears.client.Factory;
import com.google.gwt.gears.client.workerpool.WorkerPool;
import com.google.gwt.gears.client.workerpool.WorkerPoolMessageHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Sample application demonstrating how to use the {@link WorkerPool} class.
 */
public class WorkerPoolDemo implements EntryPoint, WorkerPoolMessageHandler, PiSpigot.Callback {
    private static final String INTERACTION_DESC = "<p>Notice how the browser "
            + "freezes during the synchronous calculation and some browsers alert with "
            + "a slow script warning.  During the WorkerPool calculation you can "
            + "interact with the animation and see the results updated interactively.</p>"
            + "<p><i>Note: In hosted mode, this demo works only on Windows</i></p>";

    Button startStopButton = new Button("Start");
    private RadioButton asyncCalc = new RadioButton("calcGroup", "Asynchronous (WorkerPool) code");
    private boolean calculationInProgress = false;
    private int currentRow = 0;
    private SimplePanel htmlGoesHere = new SimplePanel();
    private HTML htmlResults = new HTML();
    private ListBox numDigitsListBox = new ListBox();
    private int primeWorkerId;
    private long startTime;
    private Label statusLabel = new Label();
    private RadioButton syncCalc = new RadioButton("calcGroup", "Synchronous code");
    private VerticalPanel vp = new VerticalPanel();
    private WorkerPool workerPool = null;

    /**
     * Callback from PiSpigot class.
     */
    public void onDigits(String digits) {
        htmlResults.setHTML(htmlResults.getHTML() + "<code>" + digits + "</code><br>");
    }

    /**
     * Callback from WorkerPool class.
     */
    public void onMessageReceived(MessageEvent event) {
        assert (event.getSender() == primeWorkerId);
        if (event.getBody().startsWith("DIGITS")) {
            htmlResults.setHTML(htmlResults.getHTML() + "<code>" + event.getBody().substring(6) + "</code><br>");
        } else if (event.getBody().startsWith("MSG")) {
            htmlResults.setHTML(htmlResults.getHTML() + event.getBody().substring(4) + "<br>");
        } else if (event.getBody().equals("END")) {
            this.stopCalculation();
        } else {
            htmlResults.setHTML(htmlResults.getHTML() + "<font color=\"red\"><i>Unknown message " + event.getBody()
                    + "</i></font>");
        }
    }

    public void onModuleLoad() {

        vp.setSpacing(10);
        vp.add(buildControlPanel());
        vp.add(statusLabel);

        HorizontalPanel digitPanel = new HorizontalPanel();
        digitPanel.add(new HTML("<h1>3.</h1>"));
        digitPanel.add(htmlGoesHere);
        htmlResults.setHTML("<h1><i>???</i></h1>");
        htmlGoesHere.add(htmlResults);
        vp.add(digitPanel);
        RootPanel.get().add(vp);
    }

    private Widget buildControlPanel() {
        VerticalPanel outerPanel = new VerticalPanel();
        DecoratorPanel tableWrapper = new DecoratorPanel();
        FlexTable resultTable = new FlexTable();

        numDigitsListBox.addItem("1,000", "1000");
        numDigitsListBox.addItem("5,000", "5000");
        numDigitsListBox.addItem("10,000", "10000");
        numDigitsListBox.addItem("20,000", "20000");
        numDigitsListBox.addItem("100,000", "100000");
        buildControlPanelRow(resultTable, "Number of Digits to compute: ", numDigitsListBox);

        buildControlPanelRow(resultTable, "Execute calculation using:", syncCalc);
        syncCalc.setChecked(true);
        buildControlPanelRow(resultTable, "", asyncCalc);

        startStopButton.addClickListener(new ClickListener() {

            public void onClick(Widget sender) {
                if (calculationInProgress) {
                    statusLabel.setText(statusLabel.getText() + "...Cancelled");
                    stopCalculation();
                    return;
                }
                htmlResults.setText("");
                statusLabel.setText("Starting calculation");
                calculationInProgress = true;
                startStopButton.setEnabled(false);
                startStopButton.setText("Working...");

                startTime = System.currentTimeMillis();
                final int numDigits = Integer
                        .valueOf(numDigitsListBox.getValue(numDigitsListBox.getSelectedIndex()));
                if (syncCalc.isChecked()) {
                    /*
                     * A DeferredCommand is used here so that the previous updates to the
                     * user interface will appear. The synchronous computation will block
                     * until the calculation is complete, freezing the user interface.
                     */
                    DeferredCommand.addCommand(new Command() {
                        public void execute() {
                            doSyncCalculation(numDigits);
                        }
                    });
                } else {
                    doAsyncCalculation(numDigits);
                }
            }
        });

        buildControlPanelRow(resultTable, "", startStopButton);
        tableWrapper.setWidget(resultTable);

        // Position the Animation so that it looks centered. 
        Widget toy = new AnimationToy();
        AbsolutePanel toyWrapper = new AbsolutePanel();
        toyWrapper.setSize("450px", "210px");
        toyWrapper.add(toy, 70, 0);
        outerPanel.add(toyWrapper);

        HTML desc = new HTML(INTERACTION_DESC);
        desc.setWidth("450px");
        outerPanel.add(desc);
        outerPanel.add(tableWrapper);
        return outerPanel;
    }

    /**
     * Utility routine to construct one row of the user interface control panel.
     * 
     * @param table the table to add to.
     * @param text HTML text to add in the first column
     * @param w a widget in the control panel to add in the second column.
     */
    private void buildControlPanelRow(FlexTable table, String text, Widget w) {
        table.insertRow(currentRow);
        table.insertCell(currentRow, 0);
        table.setWidget(currentRow, 0, new HTML(text));
        table.insertCell(currentRow, 1);
        table.setWidget(currentRow, 1, w);
        currentRow++;
    }

    /**
     * Creates a worker if necessary, and sends it a message to start computing Pi
     * to the number of digits requested. The method returns immediately after
     * sending the message. Meanwhile, the computation starts to run in the worker
     * when it receives the message.
     * 
     * @param numDigits the number of digits of Pi to compute.
     */
    private void doAsyncCalculation(int numDigits) {

        if (workerPool == null) {
            workerPool = Factory.getInstance().createWorkerPool();
            primeWorkerId = workerPool.createWorkerFromUrl("pi_spigot_worker.js");
            workerPool.setMessageHandler(this);
        }
        workerPool.sendMessage("START " + numDigits, primeWorkerId);
    }

    /**
     * Computes the digits of Pi synchronously. The method will return after the
     * computation is complete.
     * 
     * @param numDigits the number of digits of Pi to compute.
     */
    private void doSyncCalculation(int numDigits) {
        PiSpigot s = new PiSpigot(numDigits, 100, this);
        s.compute();
        stopCalculation();
    }

    /**
     * Cleanup the state of the app after a computation finishes to report status
     * and prepare for the next computation.
     */
    private void stopCalculation() {
        startStopButton.setEnabled(true);
        startStopButton.setText("Start");
        calculationInProgress = false;
        long elapsed = (System.currentTimeMillis() - startTime) / 1000;
        String secondString = "seconds";
        if (elapsed == 1) {
            secondString = "second";
        }
        statusLabel.setText(elapsed + " " + secondString + " elapsed");
    }
}