Java tutorial
/* * 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"); } }