Skip to content

Commit

Permalink
New feature: uploading a file (e.g., an image) with each message.
Browse files Browse the repository at this point in the history
  • Loading branch information
Max-Hailperin committed May 8, 2012
1 parent a0e6d99 commit 4ca6c32
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 45 deletions.
109 changes: 87 additions & 22 deletions MessageBoard/src/edu/gac/mcs270/messageboard/client/MessageBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.List;

import edu.gac.mcs270.messageboard.shared.BlobService;
import edu.gac.mcs270.messageboard.shared.BlobServiceAsync;
import edu.gac.mcs270.messageboard.shared.Message;
import edu.gac.mcs270.messageboard.shared.MessageStore;
import edu.gac.mcs270.messageboard.shared.MessageStoreAsync;
Expand All @@ -13,23 +15,34 @@
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
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.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
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.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;

/**
* User interface for the message board.
* The feature to store images in Blobstore uses code taken from the BlobStore Tutorial
* written by the blogger "fishbone":
* http://www.fishbonecloud.com/2010/12/tutorial-gwt-application-for-storing.html
* @author max
*/
public class MessageBoard implements EntryPoint {
// The interval in milliseconds between periodic updates.
private static final int UPDATE_INTERVAL_MS = 10000;
private final MessageStoreAsync messageStore = GWT
.create(MessageStore.class);
private final BlobServiceAsync blobService = GWT
.create(BlobService.class);
private VerticalPanel messagesPanel;
private Label updatingLabel;
private Label failureLabel;
Expand All @@ -40,10 +53,12 @@ public class MessageBoard implements EntryPoint {
*/
public void onModuleLoad() {
final VerticalPanel mainPanel = new VerticalPanel();
final FormPanel uploadForm = new FormPanel();
final HorizontalPanel entryPanel = new HorizontalPanel();
entryPanel.addStyleName("entryPanel");
mainPanel.add(entryPanel);

mainPanel.add(uploadForm);
uploadForm.add(entryPanel);

final Label authorLabel = new Label("Author:");
final TextBox authorField = new TextBox();
entryPanel.add(authorLabel);
Expand All @@ -54,9 +69,23 @@ public void onModuleLoad() {
entryPanel.add(textLabel);
entryPanel.add(textField);

final FileUpload upload = new FileUpload();
entryPanel.add(upload);

final Button postButton = new Button("Post");
entryPanel.add(postButton);


// The upload form, when submitted, will trigger an HTTP call to the
// servlet. The following parameters must be set
uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadForm.setMethod(FormPanel.METHOD_POST);

// Set Names for the text boxes so that they can be retrieved from the
// HTTP call as parameters
authorField.setName("author");
textField.setName("text");
upload.setName("upload");

final HorizontalPanel statusPanel = new HorizontalPanel();
statusPanel.setHeight("3em");
updatingLabel = new Label("Updating...");
Expand All @@ -74,28 +103,61 @@ public void onModuleLoad() {
postButton.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
messageStore.storeMessage(
new Message(
authorField.getText(),
textField.getText()),
new AsyncCallback<Void>(){
@Override
public void onFailure(Throwable caught) {
failureLabel.setVisible(true);
}

@Override
public void onSuccess(Void result) {
failureLabel.setVisible(false);
updateMessages();
}
});
authorField.setText("");
textField.setText("");

blobService
.getBlobStoreUploadUrl(new AsyncCallback<String>() {

@Override
public void onSuccess(String result) {
// Set the form action to the newly created
// blobstore upload URL
uploadForm.setAction(result.toString());

// Submit the form to complete the upload
uploadForm.submit();
}

@Override
public void onFailure(Throwable caught) {
failureLabel.setVisible(true);
}
});

}
});

uploadForm.addSubmitHandler(new FormPanel.SubmitHandler() {
public void onSubmit(SubmitEvent event) {
// This event is fired just before the form is submitted. We can take
// this opportunity to perform validation.
if (authorField.getText().length() == 0) {
Window.alert("The author is required.");
event.cancel();
}
if (textField.getText().length() == 0) {
Window.alert("The text is required.");
event.cancel();
}
if (upload.getFilename().length() == 0) {
Window.alert("The upload file is required.");
event.cancel();
}
}
});


uploadForm
.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
@Override
public void onSubmitComplete(SubmitCompleteEvent event) {
failureLabel.setVisible(false);
updateMessages();
uploadForm.reset();
authorField.setFocus(true);
}

});

updateMessages();
new Timer(){
@Override
Expand Down Expand Up @@ -133,6 +195,9 @@ public void onSuccess(List<Message> result) {
Label heading = new Label(m.getAuthor());
heading.addStyleName("messageHeading");
messagesPanel.insert(heading, position++);
Anchor link = new Anchor("uploaded file", m.getURL());
link.setTarget("_blank");
messagesPanel.insert(link, position++);
Label body = new Label(m.getText());
body.addStyleName("messageBody");
messagesPanel.insert(body, position++);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package edu.gac.mcs270.messageboard.server;

import java.io.IOException;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.gac.mcs270.messageboard.shared.BlobService;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/* This is extracted from code in the BlobStore Tutorial written by the blogger "fishbone":
* http://www.fishbonecloud.com/2010/12/tutorial-gwt-application-for-storing.html */

@SuppressWarnings("serial")
public class BlobServiceImpl extends RemoteServiceServlet implements
BlobService {

//Start a GAE BlobstoreService session and persistence manager
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
PersistenceManager pm = PMF.get().getPersistenceManager();

//Generate a Blobstore Upload URL from the GAE BlobstoreService
@Override
public String getBlobStoreUploadUrl() {

//Map the UploadURL to the uploadservice which will be called by
//submitting the FormPanel
return blobstoreService
.createUploadUrl("/messageboard/uploadservice");
}

//Override doGet to serve blobs. This will be called when an uploaded file is viewed
//in the client
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
blobstoreService.serve(blobKey, resp);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
Expand All @@ -21,16 +20,9 @@
public class MessageStoreImpl extends RemoteServiceServlet implements
MessageStore {

private static final long serialVersionUID = 7367373321119740703L;
private static final long serialVersionUID = 2637409426426537753L;

private static final PersistenceManagerFactory pmf =
JDOHelper.getPersistenceManagerFactory("transactions-optional");

@Override
public void storeMessage(Message msg) {
PersistenceManager pm = pmf.getPersistenceManager();
pm.makePersistent(msg);
}
private static final PersistenceManagerFactory pmf = PMF.get();

@Override
public List<Message> getMessages(Long minimumID) {
Expand Down
15 changes: 15 additions & 0 deletions MessageBoard/src/edu/gac/mcs270/messageboard/server/PMF.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package edu.gac.mcs270.messageboard.server;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");

private PMF() {}

public static PersistenceManagerFactory get() {
return pmfInstance;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package edu.gac.mcs270.messageboard.server;

import java.io.IOException;
import java.util.Map;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

import edu.gac.mcs270.messageboard.shared.Message;

/* This is adapted from code in the BlobStore Tutorial written by the blogger "fishbone":
* http://www.fishbonecloud.com/2010/12/tutorial-gwt-application-for-storing.html */

//The FormPanel must submit to a servlet that extends HttpServlet
//RemoteServiceServlet cannot be used
@SuppressWarnings("serial")
public class UploadServiceImpl extends HttpServlet {

//Start Blobstore and persistence manager
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
PersistenceManager pm = PMF.get().getPersistenceManager();

//Override the doPost method to store the Blob's meta-data
@Override
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {

@SuppressWarnings("deprecation")
Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
BlobKey blobKey = blobs.get("upload");

//Get the paramters from the request to populate the Message object
Message msg =
new Message(
req.getParameter("author"),
req.getParameter("text"),
//Map the ImageURL to the blobservice servlet, which will serve the image
"/messageboard/blobservice?blob-key=" + blobKey.getKeyString()
);

pm.makePersistent(msg);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package edu.gac.mcs270.messageboard.shared;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/* This is extracted from code in the BlobStore Tutorial written by the blogger "fishbone":
* http://www.fishbonecloud.com/2010/12/tutorial-gwt-application-for-storing.html */

@RemoteServiceRelativePath("blobservice")
public interface BlobService extends RemoteService {

String getBlobStoreUploadUrl();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package edu.gac.mcs270.messageboard.shared;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface BlobServiceAsync {

void getBlobStoreUploadUrl(AsyncCallback<String> callback);

}
16 changes: 14 additions & 2 deletions MessageBoard/src/edu/gac/mcs270/messageboard/shared/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
*/
@PersistenceCapable(identityType=IdentityType.APPLICATION)
public class Message implements Serializable{
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

@Persistent
private String author;

@Persistent
private String text;

@Persistent
private String url;

@PrimaryKey
@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
Expand All @@ -29,10 +32,12 @@ public class Message implements Serializable{
/**
* @param author the name of the Message's author
* @param text the body of the Message
* @param url the URL of the uploaded file
*/
public Message(String author, String text) {
public Message(String author, String text, String url) {
this.author = author;
this.text = text;
this.url = url;
}

/**
Expand All @@ -49,6 +54,13 @@ public String getText() {
return text;
}

/**
* @return the URL of the file uploaded with this Message
*/
public String getURL() {
return url;
}

/**
* @return the id of this Message
*/
Expand Down
Loading

0 comments on commit 4ca6c32

Please sign in to comment.