Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions portfolio/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
</properties>

<dependencies>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>1.9.59</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
Expand Down
54 changes: 45 additions & 9 deletions portfolio/src/main/java/com/google/sps/servlets/DataServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,46 @@

package com.google.sps.servlets;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.HashMap;
// import java.util.ArrayList;
import com.google.gson.Gson;

/** Servlet that returns some example content. TODO: modify this file to handle comments data */
/** Servlet that adds/retrieves comments stored in a Datastore */
@WebServlet("/data")
public class DataServlet extends HttpServlet {
HashMap<String, String> messages = new HashMap<String, String>();
// ArrayList<String> messages = new ArrayList<String>();
private final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
private static final int DEFAULT_MAX_NUM_COMMENTS = 7;

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("application/json;");

Map<String, String> messages = new LinkedHashMap<>();
Query query = new Query("Comment").addSort("timestamp", SortDirection.DESCENDING);
PreparedQuery results = datastore.prepare(query);

int maxNumComments = (int)request.getSession().getAttribute("maxNumComments");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just another note here - that the session won't have this attribute on your first page load.

no need to update now, but something to ponder for future work.

for (Entity entity : results.asIterable(FetchOptions.Builder.withLimit(maxNumComments))) {
String username = (String) entity.getProperty("username");
String message = (String) entity.getProperty("message");
messages.put(username, message);
}

String json = new Gson().toJson(messages);
response.getWriter().println(json);
}
Expand All @@ -41,8 +62,23 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This post is doing two things now. It is used to post a comment and also to set the configuration property maxNumComments. Have you consider using a different Servlet to post configuration? Maybe it is overkilled, thoughts?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think each of the two things it's doing are relatively small though, especially setting the configuration property. For this example it's probably overkill, but in the future I'll be careful to scope the post method carefully.

String username = request.getParameter("username");
String message = request.getParameter("comment-or-question");
messages.put(username, message);
// messages.add(username);
String maxNumCommentsString = request.getParameter("max-num-comments");
int maxNumComments;
try {
maxNumComments = Integer.parseInt(maxNumCommentsString);
} catch (NumberFormatException e) {
System.err.format("Could not convert to int: %s%n", maxNumCommentsString);
System.err.format("Using default value of %d.%n", DEFAULT_MAX_NUM_COMMENTS);
maxNumComments = DEFAULT_MAX_NUM_COMMENTS;
}
request.getSession().setAttribute("maxNumComments", maxNumComments);

Entity commentEntity = new Entity("Comment");
commentEntity.setProperty("username", username);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constants like "Comment", "username", "message" and "timestamp" are used multiple times. Consider defining a constant for those to make it less error prone.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, I'll consider it

commentEntity.setProperty("message", message);
commentEntity.setProperty("timestamp", System.currentTimeMillis());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One notable omission here is that the comment is never added to the datastore. Do you want to add that here?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be useful for the function of the website, so I'll add it.


datastore.put(commentEntity);
response.sendRedirect("/index.html");
}
}
33 changes: 33 additions & 0 deletions portfolio/src/main/java/com/google/sps/servlets/DeleteServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.google.sps.servlets;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** Servlet that deletes data from the database. */
@WebServlet("/delete-messages")
public class DeleteServlet extends HttpServlet {

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Query query = new Query("Comment").setKeysOnly();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you missing an import here for Query?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I was.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that there are more missing imports here. (DatastoreServiceFactory, for instance).

Try invoking mvn compile to ensure that your PR is building as expected.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note that we'll probably want to find a common place to keep these constants (like "Comment") so that if they need to change, they will only need to be changed in one spot. No need to do anything now - just something to think about...

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea that could be a static class member later.

PreparedQuery preparedQuery = datastore.prepare(query);
Iterator<Entity> entities = preparedQuery.asIterator();
while (entities.hasNext()) {
Key key = entities.next().getKey();
datastore.delete(key);
}
response.sendRedirect("/index.html");
}
}
9 changes: 7 additions & 2 deletions portfolio/src/main/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</head>
<body onload="displayMessages()">
<div id="content">
<div id="opening-greeting"></div>
<h1>Ihsan Olawale's Portfolio</h1>
<p>This is Ihsan Olawale's portfolio.</p>
<p>I, Ihsan Olawale, am a STEP intern at Google. By the end of the internship I will have created a web project. This is practice.</p>
Expand All @@ -20,11 +21,15 @@ <h1>Ihsan Olawale's Portfolio</h1>
<button onclick="addRandomFact()">Learn about me</button>
<div id="fact-container"></div>
<form action="/data" method="POST">
<p>Comment here on your perception of the content. Or ask me any questions about me.</p><br/>
<p>Comment here on your perception of the content. Or ask me any questions about me.</p><br>
<input type="number" name="max-num-comments" placeholder="Max number of comments displayed"><br>
<input type="text" name="username" maxlength=10 value="username">
<textarea name="comment-or-question" rows="24" cols="80">What amazing web development this is</textarea>
<br/><br/>
<br>
<button onclick="deleteMessages()">Clear Comment History</button>
<br>
<input type="submit"/>
<br>
</form>
<div id="messages-container"></div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions portfolio/src/main/webapp/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ function displayMessages() {
}
});
}

function deleteMessages() {
fetch('/delete-messages', {method: 'POST'}).then((response) => displayMessages());
}