Categorías
Google Web Toolkit

Tutorial de GWT: Aplicación de ejemplo (1)

Bienvenido a la serie de tutoriales de GWT.

En este tutorial, primero crearé una aplicación ajax muy simple sin ninguna comunicación con el servidor o la base de datos, luego expandiré la aplicación con la base de datos y RPC. Finalmente, será una aplicación GWT completamente funcional: Quick Notes. Google App Engine es gratuito, por lo que la aplicación está activa para que la eches un vistazo. http://udnotes.appspot.com/

La aplicación de muestra finalmente se ve así.

1. Aplicación de ejemplo de GWT (1)
2. Aplicación de ejemplo de GWT (2)
3. Aplicación de ejemplo de GWT (3)

Para crear una aplicación GWT, principalmente 3 partes, sería difícil de entender para los nuevos usuarios:

  1. Cree un código del lado del cliente. Se trata de una sencilla implementación de la aplicación GUI. En lugar de usar Swing Component, usa Component de GWT.
  2. Comunicarse con el servidor con RPC. Aquí está la parte que requiere más atención.
  3. Datos de usuario de Google DataStore. La parte genial está aquí.

1. Información general.

Google Web Toolkit (GWT) es un conjunto de herramientas para desarrollar aplicaciones web Ajax utilizando Java. Una vez finalizado el código Java, el compilador GWT traduce el código Java a HTML y Javascript. En realidad, es una fuente de Java para un traductor de fuentes de JavaScript. El compilador crea HTML y JavaScript específicos del navegador para admitir correctamente todos los navegadores principales. GWT admite un conjunto estándar de widgets de interfaz de usuario, tiene soporte integrado para el botón de retroceso del navegador y un marco de prueba basado en JUnit.

2. Instale el complemento Eclipse para GWT.

Instale los complementos de http://dl.google.com/eclipse/plugin/3.6 a través del administrador de actualizaciones de Eclipse. Ayuda-> Instalar nuevo software-> Agregar este sitio y luego instalar.

3. Cree un proyecto de aplicación web de Google como este:

El paquete inicial generado automáticamente es así:

El directorio «cliente» es el lugar para colocar el código que se compila para el cliente (navegador web). Para el servicio, utilizaría el paquete «servidor». Para que podamos comenzar desde el principio, elimine todos los archivos en «cliente» y «servidor».

4. Desarrollo del lado del cliente

4.1. Punto de entrada.

Cree una clase para el punto de entrada «UDNotes».

public class UDNotes implements EntryPoint {
 
	private VerticalPanel mainPanel = new VerticalPanel();
	private FlexTable notesFlexTable = new FlexTable();
	private HorizontalPanel addPanel = new HorizontalPanel();
	private TextArea newSymbolTextBox = new TextArea();
 
 
	private Button addNoteButton = new Button("Add");
	private Label lastUpdatedLabel = new Label();
	private ArrayList<String> NotesNames = new ArrayList<String>();
 
 
	private VerticalPanel loginPanel = new VerticalPanel();
 
	public void onModuleLoad() {
 
		// Create table for Note data.
		notesFlexTable.setText(0, 0, "Note");
 
		// set button's style
		addNoteButton.addStyleName("addButton");
 
		// Assemble Add Note panel.
		addPanel.add(newSymbolTextBox);
		addPanel.add(addNoteButton);
 
		// Assemble Main panel.
		mainPanel.add(notesFlexTable);
		mainPanel.add(addPanel);
		mainPanel.add(lastUpdatedLabel);
 
		// Associate the Main panel with the HTML host page.
		RootPanel.get().add(mainPanel);
 
		// Move cursor focus to the input box.
		newSymbolTextBox.setWidth("300px");
		newSymbolTextBox.setFocus(true);
 
 
		// Listen for mouse events on the Add button.
		addNoteButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Window.alert("Button Clicked");
			}
		});
 
		// Listen for keyboard events in the input box.
		newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					Window.alert("Key Pressed");
				}
			}
		});
	}
}

Configure el archivo UDNotes.gwt.xml en el paquete com.programcreek.tutorials.

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='udnotes'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>
 
  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
 
  <!-- Other module inherits                                      -->
 
  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.programcreek.tutorials.client.UDNotes'/>
 
  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>
 
</module>

Cambie UDNotes.html en el directorio war y haga que contenga solo el siguiente código entre la etiqueta del cuerpo.

<body>
 
    <!-- OPTIONAL: include this if you want history support -->
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
 
    <!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
    <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>
Su navegador web debe tener JavaScript habilitado para que esta aplicación se muestre correctamente.

Implemente la aplicación en el motor de aplicaciones de Google.

Funcionará así:

Antes de implementar la aplicación en el motor de la aplicación, vaya al motor de la aplicación para crear un proyecto y asignar el ID correcto al proyecto.

Categorías
Google Web Toolkit

Tutorial de GWT: Aplicación de ejemplo (2)

Bienvenido a la serie de tutoriales de GWT, donde exploraremos cómo crear una aplicación GWT. Esta es la segunda parte del tutorial y trata sobre RPC y Datastore de Google App Engine. Para simplificar el contenido, se ignora el servicio de inicio de sesión. Eso significa que no necesita iniciar sesión para agregar una nota. La aplicación de muestra finalmente se ve así.

Google App Engine es gratuito, por lo que la aplicación está activa para que la eches un vistazo. http://udnotes.appspot.com/

Para crear una aplicación GWT, principalmente 3 partes, sería difícil de entender para los nuevos usuarios:

  1. Cree un código del lado del cliente. Se trata de una sencilla implementación de la aplicación GUI. En lugar de usar Swing Component, usa Component de GWT.
  2. Comunicarse con el servidor con RPC. Aquí está la parte que requiere más atención.
  3. Datos de usuario de Google DataStore. La parte genial está aquí.

Para completar una llamada RPC, se desarrollarán tres pasos. Los comentarios en la clase UDNotes explican los 3 pasos en detalle y son útiles para comprender el proceso.
1) Una interfaz con extensión RemoteService que enumera el método de servicio que necesita.
2) Una versión asincrónica de la interfaz anterior.
3) Una implementación del servicio que extiende RemoteServiceServlet implementa NoteService.

1. Cree una interfaz NoteService en el paquete «cliente».

package com.programcreek.tutorials.client;
 
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
 
@RemoteServiceRelativePath("note")
public interface NoteService extends RemoteService {
  public void addNote(String note);
  public void removeNote(String note);
  public String[] getNotes();
}

2. Cree una versión asincrónica de la interfaz en el paquete «cliente».

package com.programcreek.tutorials.client;
 
import com.google.gwt.user.client.rpc.AsyncCallback;
 
public interface NoteServiceAsync {
	void addNote(String note, AsyncCallback<Void> callback);
	void getNotes(AsyncCallback<String[]> callback);
	void removeNote(String note, AsyncCallback<Void> callback);
}

3. Cree una clase de nota en el paquete «servidor». Esto implica cómo usar JDO para almacenar datos.

package com.programcreek.tutorials.server;
 
import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
 
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Note {
 
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;
	@Persistent
	private String note;
	@Persistent
	private Date createDate;
 
	//a good way to use constructor
	public Note() {
		this.createDate = new Date();
	}
 
	public Note(String symbol) {
		this();
		this.note = symbol;
	}
 
	public Long getId() {
		return this.id;
	}
 
	public String getNote() {
		return this.note;
	}
 
	public Date getCreateDate() {
		return this.createDate;
	}
 
	public void setNote(String note) {
		this.note = note;
	}
}

4. Implemente la implementación del servicio en el paquete «servidor».

package com.programcreek.tutorials.server;
 
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
 
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
 
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.programcreek.tutorials.client.NoteService;
 
public class NoteServiceImpl extends RemoteServiceServlet implements NoteService {
 
	private static final long serialVersionUID = 1L;
 
	private static final Logger LOG = Logger.getLogger(NoteServiceImpl.class.getName());
 
	private static final PersistenceManagerFactory PMF = JDOHelper.getPersistenceManagerFactory("transactions-optional");
 
	public void addNote(String note){
		PersistenceManager pm = getPersistenceManager();
		try {
			pm.makePersistent(new Note(note));
		} finally {
			pm.close();
		}
	}
 
	public void removeNote(String note){
		PersistenceManager pm = getPersistenceManager();
		try {
			long deleteCount = 0;	
			String query = "select from " + Note.class.getName();
			List<Note> Notes = (List<Note>) pm.newQuery(query).execute();
			for (Note Note : Notes) {
				if (note.equals(Note.getNote())) {
					deleteCount++;
					pm.deletePersistent(Note);
				}
			}
			if (deleteCount != 1) {
				LOG.log(Level.WARNING, "removeNote deleted " + deleteCount
						+ " Notes");
			}
		} finally {
			pm.close();
		}
	}
 
	public String[] getNotes() {
 
		PersistenceManager pm = getPersistenceManager();
		List<String> symbols = new ArrayList<String>();
 
		try {
			String query = "select from " + Note.class.getName();
			List<Note> Notes = (List<Note>) pm.newQuery(query).execute();
 
			for (Note Note : Notes) {
				symbols.add(Note.getNote());
			}
		} finally {
			pm.close();
		}
 
		String[] ret = new String[symbols.size()];
 
		int i = 0;
		for (String s : symbols) {
			ret[i] = s;
			i++;
		}
 
		return ret;
	}
 
	private PersistenceManager getPersistenceManager() {
		return PMF.getPersistenceManager();
	}
}

5. Edite el descriptor de implementación de la aplicación web (/war/WEB-INF/web.xml).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
 
<web-app>
 
 <!-- Servlets -->  
  <servlet>
    <servlet-name>noteService</servlet-name>
    <servlet-class>com.programcreek.tutorials.server.NoteServiceImpl</servlet-class>
  </servlet>
 
 
  <servlet-mapping>
    <servlet-name>noteService</servlet-name>
    <url-pattern>/udnotes/note</url-pattern>
  </servlet-mapping>
 
  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>UDNotes.html</welcome-file>
  </welcome-file-list>
 
</web-app>

6. Edite UDNotes.java en el paquete «cliente».

 
package com.programcreek.tutorials.client;
 
import java.util.ArrayList;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
 
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class UDNotes implements EntryPoint {
 
	private VerticalPanel mainPanel = new VerticalPanel();
	private FlexTable notesFlexTable = new FlexTable();
	private HorizontalPanel addPanel = new HorizontalPanel();
	private TextArea newSymbolTextBox = new TextArea();
 
	private Button addNoteButton = new Button("Add");
	private Label lastUpdatedLabel = new Label();
	private ArrayList<String> NotesNames = new ArrayList<String>();
 
	private VerticalPanel loginPanel = new VerticalPanel();
	private Label loginLabel = new Label(
			"Please sign in to your Google Account to access the NoteWatcher application.");
 
	// (1) Create the client proxy. Note that although you are creating the
	// service interface properly, you cast the result to the asynchronous
	// version of the interface. The cast is always safe because the
	// generated proxy implements the asynchronous interface automatically.
	private final NoteServiceAsync NoteService = GWT.create(NoteService.class);
 
	public void onModuleLoad() {
 
		// Create table for Note data.
		notesFlexTable.setText(0, 0, "Note");
 
		// set button's style
		addNoteButton.addStyleName("addButton");
 
		// Assemble Add Note panel.
		addPanel.add(newSymbolTextBox);
		addPanel.add(addNoteButton);
 
		// Assemble Main panel.
		mainPanel.add(notesFlexTable);
		mainPanel.add(addPanel);
		mainPanel.add(lastUpdatedLabel);
 
		// Associate the Main panel with the HTML host page.
		RootPanel.get().add(mainPanel);
 
		// Move cursor focus to the input box.
		newSymbolTextBox.setWidth("300px");
		newSymbolTextBox.setFocus(true);
 
		// Listen for mouse events on the Add button.
		addNoteButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				addNote();
 
			}
		});
 
		// Listen for keyboard events in the input box.
		newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					addNote();
				}
			}
		});
 
		//load notes initially.
		loadNotes();
	}
 
	private void addNote() {
		final String note = newSymbolTextBox.getText().trim();
		newSymbolTextBox.setFocus(true);
		newSymbolTextBox.setText("");
 
		// Don't add the Note if it's already in the table.
		if (NotesNames.contains(note))
			return;
 
		addNote(note);
	}
 
	private void addNote(final String note) {
		// (2) Create an asynchronous callback to handle the result.
		AsyncCallback callback = new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
				// do something, when fail
				Window.alert("failed");
			}
 
			public void onSuccess(Void ignore) {
				// when successful, do something, about UI
				displayNote(note);
			}
		};
 
		// (3) Make the call. Control flow will continue immediately and later
		// 'callback' will be invoked when the RPC completes.
		NoteService.addNote(note, callback);
 
	}
 
	private void displayNote(final String note) {
		// Add the Note to the table.
		int row = notesFlexTable.getRowCount();
		NotesNames.add(note);
		notesFlexTable.setText(row, 0, note);
 
		Button removeNoteButton = new Button("x");
		removeNoteButton.addStyleDependentName("remove");
		removeNoteButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				removeNote(note);
			}
		});
		notesFlexTable.setWidget(row, 2, removeNoteButton);
 
	}
 
	private void removeNote(final String note) {
		NoteService.removeNote(note, new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
			}
 
			public void onSuccess(Void ignore) {
				undisplayNote(note);
			}
		});
	}
 
	private void undisplayNote(String note) {
		int removedIndex = NotesNames.indexOf(note);
		NotesNames.remove(removedIndex);
		notesFlexTable.removeRow(removedIndex + 1);
 
	}
 
	private void loadNotes() {
		NoteService.getNotes(new AsyncCallback<String[]>() {
			public void onFailure(Throwable error) {
			}
 
			public void onSuccess(String[] notes) {
				displayNotes(notes);
			}
		});
 
	}
 
	private void displayNotes( String[] notes) {
		for (String note : notes) {
			displayNote(note);
		}
	}
}

7. Una aplicación real es una buena forma de mostrar cómo funciona. Este ejemplo es muy básico, se pueden agregar más funciones, como servicio de inicio de sesión, control de acceso, etc.

Categorías
Google Web Toolkit

Tutorial de GWT: Aplicación de ejemplo (3)

Una vez que llegue aquí, eso significa que sabe cómo crear una aplicación GWT básica con RPC y Datastore. Ahora es posible que desee agregar control de acceso para su aplicación. Lo que necesitamos aquí es construir otro servicio. El proceso similar se aplicó aquí.

Finalmente, Class Diagram en el directorio del cliente.

NoteWatcher.java es el punto de entrada. Se enumera a continuación, solo para ideas generales. El código fuente completo se exporta a un archivo zip. Puede descargar desde http://hotfile.com/dl/101385897/0cc8202/NoteWatcher.zip.html. No hereda trabajos anteriores en 1 y 2, es otra aplicación.
(El enlace está inactivo. Lamentablemente, no tengo una copia del código porque se desarrolló hace mucho tiempo, antes de que Git se hiciera popular. Lamento las molestias, pero no tengo tiempo para hacerlo de nuevo).

package com.google.gwt.sample.notewatcher.client;
 
import java.util.ArrayList;
 
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
 
public class NoteWatcher implements EntryPoint {
 
	private VerticalPanel mainPanel = new VerticalPanel();
	private FlexTable notesFlexTable = new FlexTable();
	private HorizontalPanel addPanel = new HorizontalPanel();
	private TextArea newSymbolTextBox = new TextArea();
 
	private Button addNoteButton = new Button("Add");
	private Label lastUpdatedLabel = new Label();
	private ArrayList<String> NotesNames = new ArrayList<String>();
 
	private LoginInfo loginInfo = null;
	private VerticalPanel loginPanel = new VerticalPanel();
	private Label loginLabel = new Label(
			"Please sign in to your Google Account to access the NoteWatcher application.");
	private Anchor signInLink = new Anchor("Sign In");
	private Anchor signOutLink = new Anchor("Sign Out");
 
	// (1) Create the client proxy. Note that although you are creating the
	// service interface properly, you cast the result to the asynchronous
	// version of the interface. The cast is always safe because the
	// generated proxy implements the asynchronous interface automatically.
	private final NoteServiceAsync NoteService = GWT.create(NoteService.class);
 
	/**
	 * Entry point method.
	 */
	public void onModuleLoad() {
		// (1) Check login status using login service.
		LoginServiceAsync loginService = GWT.create(LoginService.class);
		// (2) Create an asynchronous callback to handle the result.
		AsyncCallback acb = new AsyncCallback<LoginInfo>() {
			public void onFailure(Throwable error) {
			}
 
			public void onSuccess(LoginInfo result) {
				loginInfo = result;
				if (loginInfo.isLoggedIn()) {
					loadNoteWatcher();
				} else {
					loadLogin();
				}
			}
		};
		// (3) Make the call. Control flow will continue immediately and later
		// 'callback' will be invoked when the RPC completes.
		loginService.login(GWT.getHostPageBaseURL(), acb);
	}
 
	private void loadLogin() {
		// Assemble login panel.
		signInLink.setHref(loginInfo.getLoginUrl());
		loginPanel.add(loginLabel);
		loginPanel.add(signInLink);
		RootPanel.get("noteList").add(loginPanel);
	}
 
	private void loadNoteWatcher() {
		// Set up sign out hyperlink.
		signOutLink.setHref(loginInfo.getLogoutUrl());
 
		// Create table for Note data.
		notesFlexTable.setText(0, 0, "User");
		notesFlexTable.setCellSpacing(20);
 
		notesFlexTable.setText(0, 1, "Note");
 
		if(loginInfo.getNickname() == "xiaoranlr"){
			notesFlexTable.setText(0, 2, "Remove");
		}
 
		// set button's style
		addNoteButton.addStyleName("addButton");
 
		// Assemble Add Note panel.
		addPanel.add(newSymbolTextBox);
		addPanel.add(addNoteButton);
 
 
		// Assemble Main panel.
		mainPanel.add(signOutLink);
		mainPanel.add(notesFlexTable);
		mainPanel.add(addPanel);
		mainPanel.add(lastUpdatedLabel);
 
		// Associate the Main panel with the HTML host page.
		RootPanel.get("noteList").add(mainPanel);
 
		// Move cursor focus to the input box.
		newSymbolTextBox.setWidth("300px");
		newSymbolTextBox.setFocus(true);
 
 
		// Listen for mouse events on the Add button.
		addNoteButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				addNote();
			}
		});
 
		// Listen for keyboard events in the input box.
		newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					addNote();
				}
			}
		});
 
		loadNotes();
 
	}
 
	/**
	 * Add Note to FlexTable. Executed when the user clicks the addNoteButton or
	 * presses enter in the newSymbolTextBox.
	 */
	private void addNote() {
		final String symbol = newSymbolTextBox.getText().trim();
		newSymbolTextBox.setFocus(true);
		newSymbolTextBox.setText("");
 
		// Don't add the Note if it's already in the table.
		if (NotesNames.contains(symbol))
			return;
 
		// displayNote(symbol);
		addNote(loginInfo.getNickname(), symbol);
	}
 
	private void addNote(final String user, final String symbol) {
		// (2) Create an asynchronous callback to handle the result.
		 AsyncCallback callback  = new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
				//do something, when fail
			}
 
			public void onSuccess(Void ignore) {
				//when successful, do something, about UI
				displayNote(user, symbol);
			}
		};
 
		// (3) Make the call. Control flow will continue immediately and later
		// 'callback' will be invoked when the RPC completes.
		NoteService.addNote(user, symbol, callback);
 
	}
 
	private void displayNote(final String user, final String symbol) {
		// Add the Note to the table.
		int row = notesFlexTable.getRowCount();
		NotesNames.add(symbol);
 
		notesFlexTable.setText(row, 0, user);
		notesFlexTable.setText(row, 1, symbol);
 
		// Add a button to remove this Note from the table.
		if (loginInfo.getNickname() == "xiaoranlr") {
 
			Button removeNoteButton = new Button("x");
			removeNoteButton.addStyleDependentName("remove");
			removeNoteButton.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					removeNote(symbol);
				}
			});
			notesFlexTable.setWidget(row, 2, removeNoteButton);
		}
	}
 
	private void removeNote(final String symbol) {
		NoteService.removeNote(symbol, new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
			}
 
			public void onSuccess(Void ignore) {
				undisplayNote(symbol);
			}
		});
	}
 
	private void undisplayNote(String symbol) {
		int removedIndex = NotesNames.indexOf(symbol);
		NotesNames.remove(removedIndex);
		notesFlexTable.removeRow(removedIndex + 1);
 
	}
 
	private void loadNotes() {
		NoteService.getNotes(new AsyncCallback<String[]>() {
			public void onFailure(Throwable error) {
			}
 
			public void onSuccess(String[] symbols) {
				displayNotes("anonymous", symbols);
			}
		});
 
	}
 
	private void displayNotes(String user, String[] symbols) {
		for (String symbol : symbols) {
			displayNote(user, symbol);
		}
	}
 
}