From 47daa08bdb761926ea9ae35dbf9792ecac4f1c79 Mon Sep 17 00:00:00 2001 From: Brian Hannaway Date: Sun, 23 Sep 2012 12:43:40 +0100 Subject: [PATCH] initial commit --- .gitattributes | 22 ++ .gitignore | 163 +++++++++++++ rest-sample/pom.xml | 104 +++++++++ .../java/com/blog/samples/domain/Fund.java | 118 ++++++++++ .../blog/samples/services/FundService.java | 107 +++++++++ .../samples/web/utils/DateSerializer.java | 27 +++ .../webservices/rest/FundsController.java | 217 ++++++++++++++++++ rest-sample/src/main/resources/log4j.xml | 46 ++++ .../src/main/webapp/META-INF/context.xml | 5 + .../WEB-INF/config/rest-services-config.xml | 58 +++++ rest-sample/src/main/webapp/WEB-INF/web.xml | 51 ++++ 11 files changed, 918 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 rest-sample/pom.xml create mode 100644 rest-sample/src/main/java/com/blog/samples/domain/Fund.java create mode 100644 rest-sample/src/main/java/com/blog/samples/services/FundService.java create mode 100644 rest-sample/src/main/java/com/blog/samples/web/utils/DateSerializer.java create mode 100644 rest-sample/src/main/java/com/blog/samples/webservices/rest/FundsController.java create mode 100644 rest-sample/src/main/resources/log4j.xml create mode 100644 rest-sample/src/main/webapp/META-INF/context.xml create mode 100644 rest-sample/src/main/webapp/WEB-INF/config/rest-services-config.xml create mode 100644 rest-sample/src/main/webapp/WEB-INF/web.xml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ebd21a --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/rest-sample/pom.xml b/rest-sample/pom.xml new file mode 100644 index 0000000..49f6f7e --- /dev/null +++ b/rest-sample/pom.xml @@ -0,0 +1,104 @@ + + + rest-sample + 4.0.0 + 2011 + war + com.blog.rest + 1.0 + + 1 + 3.1.1.RELEASE + 1.5 + 1.5.6 + UTF-8 + UTF-8 + 2.7 + 1.1.1 + 1.2.16 + rest-sample + 1.5.6 + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-war-plugin + + ${context.path} + + + + + + + log4j + log4j + ${log4j.version} + + + org.springframework + spring-core + ${spring.version} + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-aop + ${spring.version} + + + org.springframework + spring-aspects + ${spring.version} + + + org.springframework + spring-asm + ${spring.version} + + + org.springframework + spring-expression + ${spring.version} + + + org.springframework + spring-web + ${spring.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + org.codehaus.jackson + jackson-mapper-asl + ${jackson.mapper.version} + + + javax.servlet + servlet-api + 2.4 + + + \ No newline at end of file diff --git a/rest-sample/src/main/java/com/blog/samples/domain/Fund.java b/rest-sample/src/main/java/com/blog/samples/domain/Fund.java new file mode 100644 index 0000000..6ec84dd --- /dev/null +++ b/rest-sample/src/main/java/com/blog/samples/domain/Fund.java @@ -0,0 +1,118 @@ +package com.blog.samples.domain; + +import java.util.Date; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import com.blog.samples.web.utils.DateSerializer; + +/** + * The Class Fund. + */ +public class Fund{ + + private String fundId; + private String fundDescription; + private double bidPrice; + private double offerPrice; + private Date lastUpdated; + + public Fund() + { } + + /** + * Gets the fund id. + * + * @return the fund id + */ + public String getFundId() { + return fundId; + } + + /** + * Sets the fund id. + * + * @param fundId the new fund id + */ + public void setFundId(String fundId) { + this.fundId = fundId; + } + + /** + * Gets the fund description. + * + * @return the fund description + */ + public Object getFundDescription() { + return fundDescription; + } + + /** + * Sets the fund description. + * + * @param fundDescription the new fund description + */ + public void setFundDescription(String fundDescription) { + this.fundDescription = fundDescription; + } + + /** + * Gets the bid price. + * + * @return the bid price + */ + public double getBidPrice() { + return bidPrice; + } + + /** + * Sets the bid price. + * + * @param bidPrice the new bid price + */ + public void setBidPrice(double bidPrice) { + this.bidPrice = bidPrice; + } + + /** + * Gets the offer price. + * + * @return the offer price + */ + public double getOfferPrice() { + return offerPrice; + } + + /** + * Sets the offer price. + * + * @param offerPrice the new offer price + */ + public void setOfferPrice(double offerPrice) { + this.offerPrice = offerPrice; + } + + /** + * Gets the last updated. + * + * @return the last updated + */ + @JsonSerialize(using=DateSerializer.class) + public Date getLastUpdated() { + return lastUpdated; + } + + /** + * Sets the last updated. + * + * @param lastUpdated the new last updated + */ + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + @Override + public String toString() { + return "Fund [fundId=" + fundId + ", fundDescription=" + + fundDescription + ", bidPrice=" + bidPrice + ", offerPrice=" + + offerPrice + ", lastUpdated=" + lastUpdated + "]"; + } +} diff --git a/rest-sample/src/main/java/com/blog/samples/services/FundService.java b/rest-sample/src/main/java/com/blog/samples/services/FundService.java new file mode 100644 index 0000000..3d01849 --- /dev/null +++ b/rest-sample/src/main/java/com/blog/samples/services/FundService.java @@ -0,0 +1,107 @@ +package com.blog.samples.services; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Service; + +import com.blog.samples.domain.Fund; + +/** + * The Class FundService. + */ +@Service +public class FundService { + + private static final Logger logger_c = Logger.getLogger(FundService.class); + + /** + * Get the fund by id. + * + * @param fundId_p + * the fund id_p + * @return the fund by id + */ + public Fund getFundById(String fundId_p) { + Fund fund = new Fund(); + + fund.setFundId(fundId_p); + fund.setFundDescription("High Risk Equity Fund"); + fund.setBidPrice(26.80); + fund.setOfferPrice(27.40); + fund.setLastUpdated(new Date()); + + return fund; + } + + /** + * Gets all funds. + * + * @return the all funds + */ + public List getAllFunds() { + List funds = new ArrayList(); + + for (int i = 0; i < 10; i++) { + Fund fund = new Fund(); + + fund.setFundId("12345" + i); + fund.setFundDescription("High Risk Equity Fund " + (i + 1)); + fund.setBidPrice(26.80 + (Math.random() * 10)); + fund.setOfferPrice(27.40 + (Math.random() * 10)); + fund.setLastUpdated(new Date()); + + funds.add(fund); + } + + return funds; + } + + /** + * Creates the fund. + * + * @param fund_p + * the fund_p + * @return the fund + */ + public Fund createFund(Fund fund_p) { + + logger_c.debug("Persisting fund in database: " + fund_p.toString()); + + /* set id and timestamp */ + fund_p.setFundId("12345"); + fund_p.setLastUpdated(new Date()); + + return fund_p; + } + + /** + * Update fund. + * + * @param fund_p + * the fund_p + * @return the fund + */ + public Fund updateFund(Fund fund_p) { + + logger_c.debug("Updating fund in database: " + fund_p.toString()); + + /* set timestamp */ + fund_p.setLastUpdated(new Date()); + + return fund_p; + } + + /** + * Delete fund. + * + * @param fundId_p + * the fund id_p + */ + public void deleteFund(String fundId_p) { + logger_c.debug("Deleting fund from database: " + fundId_p.toString()); + + } + +} diff --git a/rest-sample/src/main/java/com/blog/samples/web/utils/DateSerializer.java b/rest-sample/src/main/java/com/blog/samples/web/utils/DateSerializer.java new file mode 100644 index 0000000..a19101b --- /dev/null +++ b/rest-sample/src/main/java/com/blog/samples/web/utils/DateSerializer.java @@ -0,0 +1,27 @@ +package com.blog.samples.web.utils; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import org.codehaus.jackson.JsonGenerator; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.JsonSerializer; +import org.codehaus.jackson.map.SerializerProvider; + +/** + * The Class DateSerializer. + */ +public class DateSerializer extends JsonSerializer { + + /* (non-Javadoc) + * @see org.codehaus.jackson.map.JsonSerializer#serialize(java.lang.Object, org.codehaus.jackson.JsonGenerator, org.codehaus.jackson.map.SerializerProvider) + */ + @Override + public void serialize(Date value_p, JsonGenerator gen, SerializerProvider prov_p) + throws IOException, JsonProcessingException + { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + String formattedDate = formatter.format(value_p); + gen.writeString(formattedDate); + } +} \ No newline at end of file diff --git a/rest-sample/src/main/java/com/blog/samples/webservices/rest/FundsController.java b/rest-sample/src/main/java/com/blog/samples/webservices/rest/FundsController.java new file mode 100644 index 0000000..646db0a --- /dev/null +++ b/rest-sample/src/main/java/com/blog/samples/webservices/rest/FundsController.java @@ -0,0 +1,217 @@ +package com.blog.samples.webservices.rest; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; + +import com.blog.samples.domain.Fund; +import com.blog.samples.services.FundService; + +/** + * FundsController class will expose a series of RESTful endpoints + */ +@Controller +public class FundsController { + + @Autowired + private FundService fundService_i; + + @Autowired + private View jsonView_i; + + private static final String DATA_FIELD = "data"; + private static final String ERROR_FIELD = "error"; + + private static final Logger logger_c = Logger.getLogger(FundsController.class); + + /** + * Gets a fund by fund id. + * + * @param fundId_p + * the fund id_p + * @return the fund + */ + @RequestMapping(value = "/rest/funds/{fundId}", method = RequestMethod.GET) + public ModelAndView getFund(@PathVariable("fundId") String fundId_p) { + Fund fund = null; + + /* validate fund Id parameter */ + if (isEmpty(fundId_p) || fundId_p.length() < 5) { + String sMessage = "Error invoking getFund - Invalid fund Id parameter"; + return createErrorResponse(sMessage); + } + + try { + fund = fundService_i.getFundById(fundId_p); + } catch (Exception e) { + String sMessage = "Error invoking getFund. [%1$s]"; + return createErrorResponse(String.format(sMessage, e.toString())); + } + + logger_c.debug("Returing Fund: " + fund.toString()); + return new ModelAndView(jsonView_i, DATA_FIELD, fund); + } + + /** + * Gets all funds. + * + * @return the funds + */ + @RequestMapping(value = "/rest/funds/", method = RequestMethod.GET) + public ModelAndView getFunds() { + List funds = null; + + try { + funds = fundService_i.getAllFunds(); + } catch (Exception e) { + String sMessage = "Error getting all funds. [%1$s]"; + return createErrorResponse(String.format(sMessage, e.toString())); + } + + logger_c.debug("Returing Funds: " + funds.toString()); + return new ModelAndView(jsonView_i, DATA_FIELD, funds); + } + + /** + * Creates a new fund. + * + * @param fund_p + * the fund_p + * @return the model and view + */ + @RequestMapping(value = { "/rest/funds/" }, method = { RequestMethod.POST }) + public ModelAndView createFund(@RequestBody Fund fund_p, + HttpServletResponse httpResponse_p, WebRequest request_p) { + + Fund createdFund; + logger_c.debug("Creating Fund: " + fund_p.toString()); + + try { + createdFund = fundService_i.createFund(fund_p); + } catch (Exception e) { + String sMessage = "Error creating new fund. [%1$s]"; + return createErrorResponse(String.format(sMessage, e.toString())); + } + + /* set HTTP response code */ + httpResponse_p.setStatus(HttpStatus.CREATED.value()); + + /* set location of created resource */ + httpResponse_p.setHeader("Location", request_p.getContextPath() + "/rest/funds/" + fund_p.getFundId()); + + /** + * Return the view + */ + return new ModelAndView(jsonView_i, DATA_FIELD, createdFund); + } + + /** + * Updates fund with given fund id. + * + * @param fund_p + * the fund_p + * @return the model and view + */ + @RequestMapping(value = { "/rest/funds/{fundId}" }, method = { RequestMethod.PUT }) + public ModelAndView updateFund(@RequestBody Fund fund_p, @PathVariable("fundId") String fundId_p, + HttpServletResponse httpResponse_p) { + + logger_c.debug("Updating Fund: " + fund_p.toString()); + + /* validate fund Id parameter */ + if (isEmpty(fundId_p) || fundId_p.length() < 5) { + String sMessage = "Error updating fund - Invalid fund Id parameter"; + return createErrorResponse(sMessage); + } + + Fund fund = null; + + try { + fund = fundService_i.updateFund(fund_p); + } catch (Exception e) { + String sMessage = "Error updating fund. [%1$s]"; + return createErrorResponse(String.format(sMessage, e.toString())); + } + + httpResponse_p.setStatus(HttpStatus.OK.value()); + return new ModelAndView(jsonView_i, DATA_FIELD, fund); + } + + /** + * Deletes the fund with the given fund id. + * + * @param fundId_p + * the fund id_p + * @return the model and view + */ + @RequestMapping(value = "/rest/funds/{fundId}", method = RequestMethod.DELETE) + public ModelAndView removeFund(@PathVariable("fundId") String fundId_p, + HttpServletResponse httpResponse_p) { + + logger_c.debug("Deleting Fund Id: " + fundId_p.toString()); + + /* validate fund Id parameter */ + if (isEmpty(fundId_p) || fundId_p.length() < 5) { + String sMessage = "Error deleting fund - Invalid fund Id parameter"; + return createErrorResponse(sMessage); + } + + try { + fundService_i.deleteFund(fundId_p); + } catch (Exception e) { + String sMessage = "Error invoking getFunds. [%1$s]"; + return createErrorResponse(String.format(sMessage, e.toString())); + } + + httpResponse_p.setStatus(HttpStatus.OK.value()); + return new ModelAndView(jsonView_i, DATA_FIELD, null); + } + + public static boolean isEmpty(String s_p) { + return (null == s_p) || s_p.trim().length() == 0; + } + + /** + * Create an error REST response. + * + * @param sMessage + * the s message + * @return the model and view + */ + private ModelAndView createErrorResponse(String sMessage) { + return new ModelAndView(jsonView_i, ERROR_FIELD, sMessage); + } + + /** + * Injector methods. + * + * @param fundService_p + * the new fund service + */ + public void setFundService(FundService fundService_p) { + fundService_i = fundService_p; + } + + /** + * Injector methods. + * + * @param view + * the new json view + */ + public void setJsonView(View view) { + jsonView_i = view; + } + +} diff --git a/rest-sample/src/main/resources/log4j.xml b/rest-sample/src/main/resources/log4j.xml new file mode 100644 index 0000000..7c559b9 --- /dev/null +++ b/rest-sample/src/main/resources/log4j.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rest-sample/src/main/webapp/META-INF/context.xml b/rest-sample/src/main/webapp/META-INF/context.xml new file mode 100644 index 0000000..9e8bcf6 --- /dev/null +++ b/rest-sample/src/main/webapp/META-INF/context.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/rest-sample/src/main/webapp/WEB-INF/config/rest-services-config.xml b/rest-sample/src/main/webapp/WEB-INF/config/rest-services-config.xml new file mode 100644 index 0000000..7e10511 --- /dev/null +++ b/rest-sample/src/main/webapp/WEB-INF/config/rest-services-config.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rest-sample/src/main/webapp/WEB-INF/web.xml b/rest-sample/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..e3c5059 --- /dev/null +++ b/rest-sample/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,51 @@ + + + + REST Sample + + + + contextConfigLocation + + /WEB-INF/config/rest-services-config.xml + + + + + + org.springframework.web.context.ContextLoaderListener + + + + + restservices + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + + + 1 + + + + + restservices + / + + + \ No newline at end of file