package org.tokenator.opentokenizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.tokenator.opentokenizer.domain.entity.PrimaryData; import org.tokenator.opentokenizer.domain.entity.SurrogateData; import org.tokenator.opentokenizer.domain.repository.PrimaryDataRepository; import org.tokenator.opentokenizer.domain.repository.SurrogateDataRepository; import org.tokenator.opentokenizer.util.LuhnUtil; import javax.transaction.Transactional; import java.util.Date; import static org.tokenator.opentokenizer.util.DateSerializer.DATE_FORMAT; @RestController @RequestMapping("/api/v1") public class ApiController { private PrimaryDataRepository primaryDataRepo; private SurrogateDataRepository surrogateDataRepo; @Autowired public ApiController( PrimaryDataRepository primaryDataRepo, SurrogateDataRepository surrogateDataRepo ) { this.primaryDataRepo = primaryDataRepo; this.surrogateDataRepo = surrogateDataRepo; } /* * Create a primary data entry. Example: * * $ curl -X POST -H 'Content-Type: application/json' -d '{"pan": "4046460664629718", "expr": "1801"}' \ * http://localhost:8080/api/v1/primaries/ */ @RequestMapping( value = "/primaries", method = RequestMethod.POST ) @ResponseStatus(HttpStatus.CREATED) public PrimaryData createPrimary(@RequestBody PrimaryData primaryData) { primaryData.setPan(LuhnUtil.validateAcctNumAndAdjustLuhn(primaryData.getPan())); return primaryDataRepo.save(primaryData); } /* * Lookup primary PAN data by id. Example retrieving primary data for id=1: * * $ curl -X GET http://localhost:8080/api/v1/primaries/1 */ @RequestMapping( value = "/primaries/{id}", method = RequestMethod.GET ) @ResponseStatus(HttpStatus.CREATED) public PrimaryData findPrimaryById(@PathVariable(value="id") Long id) { PrimaryData primary = primaryDataRepo.findOne(id); if (primary == null) { throw new EntityNotFoundException(PrimaryData.class, id); } return primary; } /* * Lookup primary data by pan and yyMM expiration date. Example: * * $ curl -X GET http://localhost:8080/api/v1/primaries/4046460664629718/1801 */ @RequestMapping( value = "/primaries/{pan}/{expr}", method = RequestMethod.GET ) @ResponseStatus(HttpStatus.OK) public PrimaryData findPrimaryByPanAndExpr( @PathVariable(value="pan") String pan, @PathVariable(value="expr") @DateTimeFormat(pattern = DATE_FORMAT) Date expr) { PrimaryData primary = primaryDataRepo.findByPanAndExpr(pan, expr); if (primary == null) { throw new EntityNotFoundException(PrimaryData.class, pan, expr); } return primary; } /* * Delete primary entry by id. Surrogates are deleted by cascade. Example: * * $ curl -X DELETE http://localhost:8080/api/v1/primaries/1 */ @RequestMapping( value = "/primaries/{id}", method = RequestMethod.DELETE ) @ResponseStatus(HttpStatus.NO_CONTENT) /* 204, success but no response payload */ public void deletePrimaryById(@PathVariable(value="id") long primaryId) { primaryDataRepo.delete(primaryId); } /* * Create a surrogate for a primary data entry with the specified id. Example: * * $ curl -X POST -H 'Content-Type: application/json' -d '{"pan": "98765432109876", "expr": "1801"}' \ * http://localhost:8080/api/v1/primaries/1/surrogates/ */ @RequestMapping( value = "/primaries/{primaryId}/surrogates/", method = RequestMethod.POST ) @ResponseStatus(HttpStatus.CREATED) @Transactional public SurrogateData createSurrogate( @PathVariable(value="primaryId") Long primaryId, @RequestBody SurrogateData surrogateData) { PrimaryData primary = primaryDataRepo.findOne(primaryId); if (primary == null) { throw new EntityNotFoundException(PrimaryData.class, primaryId); } surrogateData.setSan(LuhnUtil.validateAcctNumAndAdjustLuhn(surrogateData.getSan())); primary.addSurrogate(surrogateData); return surrogateData; } /* * Find the primary data that owns the requested surrogate pan+expr. Example: * * $ curl -X GET http://localhost:8080/api/v1/primaries/surrogates/98765432109876/1801 */ @RequestMapping( value = "/primaries/surrogates/{san}/{expr}", method = RequestMethod.GET ) @ResponseStatus(HttpStatus.OK) public PrimaryData findPrimaryOfSurrogate( @PathVariable(value="san") String san, @PathVariable(value="expr") @DateTimeFormat(pattern = DATE_FORMAT) Date expr) { PrimaryData primary = primaryDataRepo.findBySurrogate(san, expr); if (primary == null) { throw new EntityNotFoundException(SurrogateData.class, san, expr); } return primary; } /* * Delete surrogate entry by id. Example * * $ curl -X DELETE http://localhost:8080/api/v1/surrogates/1 */ @RequestMapping( value = "/surrogates/{surrogateId}", method = RequestMethod.DELETE ) @ResponseStatus(HttpStatus.NO_CONTENT) /* 204, success but no response payload */ @Transactional public void deleteSurrogate(@PathVariable(value="surrogateId") long surrogateId) { surrogateDataRepo.delete(surrogateId); } @ExceptionHandler(EmptyResultDataAccessException.class) @ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Entity not found") public void notFound() { } @ExceptionHandler(DataIntegrityViolationException.class) @ResponseStatus(value=HttpStatus.CONFLICT,reason="Entity already exists") public void duplicateEntryExists() { } }