diff --git a/pom.xml b/pom.xml
index ed84c9b..fab15cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,7 +15,7 @@
UTF-8
- io.zipcoder.tc_spring_poll_application.QuickPollApplication
+ io.zipcoder.springdemo.QuickPollApplication
1.7
diff --git a/src/main/java/dtos/OptionCount.java b/src/main/java/dtos/OptionCount.java
new file mode 100644
index 0000000..cdf9522
--- /dev/null
+++ b/src/main/java/dtos/OptionCount.java
@@ -0,0 +1,22 @@
+package dtos;
+
+public class OptionCount {
+ private Long optionId;
+ private int count;
+
+ public Long getOptionId() {
+ return optionId;
+ }
+
+ public void setOptionId(Long optionId) {
+ this.optionId = optionId;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+}
diff --git a/src/main/java/dtos/VoteResult.java b/src/main/java/dtos/VoteResult.java
new file mode 100644
index 0000000..b3d873d
--- /dev/null
+++ b/src/main/java/dtos/VoteResult.java
@@ -0,0 +1,24 @@
+package dtos;
+
+import java.util.Collection;
+
+public class VoteResult {
+ private int totalVotes;
+ private Collection results;
+
+ public int getTotalVotes() {
+ return totalVotes;
+ }
+
+ public void setTotalVotes(int totalVotes) {
+ this.totalVotes = totalVotes;
+ }
+
+ public Collection getResults() {
+ return results;
+ }
+
+ public void setResults(Collection results) {
+ this.results = results;
+ }
+}
diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java
new file mode 100644
index 0000000..385ebc5
--- /dev/null
+++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java
@@ -0,0 +1,51 @@
+package io.zipcoder.tc_spring_poll_application.controller;
+
+import dtos.OptionCount;
+import dtos.VoteResult;
+import io.zipcoder.tc_spring_poll_application.domain.Vote;
+import io.zipcoder.tc_spring_poll_application.repositories.VoteRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+public class ComputeResultController {
+
+ private VoteRepository voteRepository;
+
+ @Autowired
+ public ComputeResultController(VoteRepository voteRepository){
+ this.voteRepository = voteRepository;
+ }
+
+ @RequestMapping(value = "/computeresult", method = RequestMethod.GET)
+ public ResponseEntity> computeResult(@RequestParam Long pollId){ //requestparam annotation instructs SPring to retrieve the pollId value from a HTTP query
+ VoteResult voteResult = new VoteResult();
+ Iterable allVotes = voteRepository.findVotesByPoll(pollId);
+
+ int totalVotes = 0;
+ Map tempMap = new HashMap<>();
+ for(Vote v : allVotes) {
+ totalVotes ++;
+ // Get the OptionCount corresponding to this Option
+ OptionCount optionCount = tempMap.get(v.getOption().getId());
+ if(optionCount == null) {
+ optionCount = new OptionCount();
+ optionCount.setOptionId(v.getOption().getId());
+ tempMap.put(v.getOption().getId(), optionCount);
+ }
+ optionCount.setCount(optionCount.getCount()+1);
+ }
+ voteResult.setTotalVotes(totalVotes);
+ voteResult.setResults(tempMap.values());
+
+ return new ResponseEntity<>(voteResult, HttpStatus.OK); //computes results sent to client using new response entity
+ }
+}
diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java
new file mode 100644
index 0000000..0b0ad2d
--- /dev/null
+++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java
@@ -0,0 +1,79 @@
+package io.zipcoder.tc_spring_poll_application.controller;
+
+import io.zipcoder.tc_spring_poll_application.domain.Poll;
+import io.zipcoder.tc_spring_poll_application.exception.ResourceNotFoundException;
+import io.zipcoder.tc_spring_poll_application.repositories.PollRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+import javax.validation.Valid;
+import java.net.URI;
+
+@RestController// marks entity as a controller following REST specs
+public class PollController {
+
+ private PollRepository pollRepository;
+
+ @Autowired //The @Autowired annotation allows you to skip configurations elsewhere of what to inject and just does it for you
+ public PollController(PollRepository pollRepository){
+ this.pollRepository = pollRepository;
+ }
+
+ @RequestMapping(value="/polls", method= RequestMethod.GET)//maps web requests to entities with the @RequestMapping
+ public ResponseEntity> getAllPolls(Pageable pageable) {
+ Page allPolls = pollRepository.findAll(pageable); //essentially pages the data
+ return new ResponseEntity<>(allPolls, HttpStatus.OK);// returns paged data
+ }
+
+ @RequestMapping(value="/polls", method=RequestMethod.POST)
+ public ResponseEntity> createPoll(@RequestBody Poll poll) { //@RequestBody tells Spring that the entire request body needs to be converted to an instance of Poll
+ poll = pollRepository.save(poll);
+ HttpHeaders newHeaders = new HttpHeaders();
+
+ URI newPollUri = ServletUriComponentsBuilder //allows the client to have a way to know the uri of the created poll
+ .fromCurrentRequest()
+ .path("/{id}")
+ .buildAndExpand(poll.getId())
+ .toUri();
+ newHeaders.setLocation(newPollUri);
+ return new ResponseEntity<>(newHeaders, HttpStatus.CREATED);
+ }
+
+ @Valid
+ @RequestMapping(value="/polls/{pollId}", method=RequestMethod.GET)
+ public ResponseEntity> getPoll(@PathVariable Long pollId) {
+ verifyPoll(pollId);
+ Poll p = pollRepository.findOne(pollId);
+ return new ResponseEntity<> (p, HttpStatus.OK);
+ }
+
+ @Valid
+ @RequestMapping(value="/polls/{pollId}", method=RequestMethod.PUT)
+ public ResponseEntity> updatePoll(@RequestBody Poll poll, @PathVariable Long pollId) {
+ // Save the entity
+ verifyPoll(pollId);
+ Poll p = pollRepository.save(poll);
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ @RequestMapping(value="/polls/{pollId}", method=RequestMethod.DELETE)
+ public ResponseEntity> deletePoll(@PathVariable Long pollId) {
+ verifyPoll(pollId);
+ pollRepository.delete(pollId);
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ public void verifyPoll(Long pollId){
+ Poll poll = pollRepository.findOne(pollId);
+ if(poll == null){
+ throw new ResourceNotFoundException("The given poll id " + pollId + " does not exist!");
+ }
+ }
+
+}
diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java
new file mode 100644
index 0000000..7a9bb10
--- /dev/null
+++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java
@@ -0,0 +1,43 @@
+package io.zipcoder.tc_spring_poll_application.controller;
+
+import io.zipcoder.tc_spring_poll_application.domain.Vote;
+import io.zipcoder.tc_spring_poll_application.repositories.VoteRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+
+@RestController
+public class VoteController {
+
+ private VoteRepository voteRepository;
+
+ @Autowired
+ public VoteController(VoteRepository voteRepository) {
+ this.voteRepository = voteRepository;
+ }
+
+ @RequestMapping(value = "/polls/{pollId}/votes", method = RequestMethod.POST)
+ public ResponseEntity> createVote(@PathVariable Long pollId, @RequestBody Vote
+ vote) {
+ vote = voteRepository.save(vote);
+ // Set the headers for the newly created resource
+ HttpHeaders responseHeaders = new HttpHeaders();
+ responseHeaders.setLocation(ServletUriComponentsBuilder.
+ fromCurrentRequest().path("/{id}").buildAndExpand(vote.getId()).toUri());
+ return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
+ }
+
+ @RequestMapping(value="/polls/votes", method=RequestMethod.GET)
+ public Iterable getAllVotes() {
+ return voteRepository.findAll();
+ }
+
+ @RequestMapping(value="/polls/{pollId}/votes", method=RequestMethod.GET)
+ public Iterable getVote(@PathVariable Long pollId) {
+ return voteRepository.findVotesByPoll(pollId);
+ }
+}
diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java
new file mode 100644
index 0000000..82ca99d
--- /dev/null
+++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java
@@ -0,0 +1,35 @@
+package io.zipcoder.tc_spring_poll_application.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity // this means that a class can be mapped to a table. Just is a marker like Serializable
+public class Option {
+
+ @Id // specifies primary key of entity (primary key is a special column)
+ @GeneratedValue // configures the way of increment of the specified column (field)
+ @Column(name = "OPTION_ID")// specifies mapped column for a persistence property. Without this annotation the framework assumes the field's variable-name is the persistent property
+ private Long id;
+
+ @Column(name = "OPTION_VALUE")// specifies mapped column for persistence value
+ private String value;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+}
diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java
new file mode 100644
index 0000000..c3e8b3f
--- /dev/null
+++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java
@@ -0,0 +1,50 @@
+package io.zipcoder.tc_spring_poll_application.domain;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.persistence.*;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+@Entity
+public class Poll {
+
+ @Id
+ @GeneratedValue
+ @Column(name = "POLL_ID")
+ private Long id;
+
+ @NotEmpty
+ @Column(name = "QUESTION")
+ private String question;
+
+ @Size(min=2, max = 6)
+ @OneToMany(cascade = CascadeType.ALL)// indicates that a Poll instance can contain zero or more Option instances. The CascadeType.All indicates that any database operations such as persist, remove, or merge on a Poll instance needs to be propagated to all related Option instances
+ @JoinColumn(name = "POLL_ID")// indicates this entity is the owner of the relationship. It has a key to the column with options
+ @OrderBy// orders by ASC default
+ private Set