Skip to content

Instantly share code, notes, and snippets.

@elsewhat
Created May 19, 2012 14:10
Show Gist options
  • Save elsewhat/2730948 to your computer and use it in GitHub Desktop.
Save elsewhat/2730948 to your computer and use it in GitHub Desktop.
FeedResource (Jersey REST API)
package no.bouvet.sap.neo.rest;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.sql.DataSource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.persistence.FeedEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* REST API for the FeedEntry class
*
* Uses annotations from JAX-RS and JAXB
* Is called from the Jersey servlet com.sun.jersey.spi.container.servlet.ServletContainer
*
* @author dagfinn.parnas@bouvet.no
*/
@Path("/feed")
public class FeedResource {
final Logger logger = LoggerFactory.getLogger(FeedResource.class);
@Context
UriInfo uriInfo;
@Context
Request request;
private static DataSource ds;
private static EntityManagerFactory emf;
/**
* Constructor needs to have no parameters.
* It will initialize the datasource we are using (JPA)
*
*/
public FeedResource(){
try {
initPersistencyLayer();
}catch (Exception e) {
//TODO: Handle better
logger.error("Failed to initialize persistency layer", e);
}
}
/**
* Main method that returns all feeds in the persistency layer.
* It can produce the content in either JSON or XML (based on client preferences)
*
* Curl example (return all feeds in json format):
* $ curl -i -H "Accept: application/json"
* http://localhost:8080/feed_stream/api/feed/
*
* @return
*/
@GET
@Produces( { MediaType.APPLICATION_JSON , MediaType.APPLICATION_XML})
public List<FeedEntry> getAllFeedEntries() {
//Get all feed entries from persistency layer
EntityManager em = emf.createEntityManager();
List<FeedEntry> resultList = em.createNamedQuery("AllFeedEntries",
FeedEntry.class).getResultList();
//Logging
String message = (resultList==null)? "getAllFeedEntries returning null": "getAllFeedEntries returning " + resultList.size() + " entries";
logger.debug(message);
return resultList;
}
/**
* Method that returns all feeds in the persistency layer.
* Can be used for testing in the browser
*
* @return
*/
@GET
@Produces( { MediaType.TEXT_XML })
public List<FeedEntry> getAllFeedEntriesForHTML() {
EntityManager em = emf.createEntityManager();
List<FeedEntry> resultList = em.createNamedQuery("AllFeedEntries",
FeedEntry.class).getResultList();
//Logging
String message = (resultList==null)? "getAllFeedEntries returning null": "getAllFeedEntries returning " + resultList.size() + " entries";
logger.debug(message);
return resultList;
}
/**
* Return a single feed entry based on ID
* Will be called if request has syntax /feed/<feed id>
* It can produce the content in either JSON or XML (based on client preferences)
*
* Curl example (return feed with id 2)
* $ curl -i -H "Accept: application/json"
* http://localhost:8080/feed_stream/api/feed/2
*
*
* @param feedId
* @return The encoded FeedEntry or null if not FeedEntry matches
*/
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("{feedid}/")
public FeedEntry getSingleFeed(@PathParam("feedid") String strFeedId) {
EntityManager em = emf.createEntityManager();
//Logging
logger.error("getSingleFeed with id:"+ strFeedId + " called");
try {
long feedId = Long.parseLong(strFeedId);
FeedEntry feedEntry = em.find(FeedEntry.class, feedId);
return feedEntry;
}catch (NumberFormatException e1) {
// TODO: Input parameter is not a long and therefore not a valid primary key
logger.warn("getSingleFeed for " + strFeedId + " is not a valid key", e1);
}catch (IllegalArgumentException e2){
//Invalid type of parameter . Should not happen normally
logger.warn("getSingleFeed for " + strFeedId + " gave exception", e2);
}
return null;
}
/**
* PUT a new object and store it in the persistency layer
* Must be called from with the HTTP PUT method
* and accepts input in both JSON and XML format.
*
* Curl example (creates new feed):
* $ curl -i -X PUT -H 'Content-Type: application/json'
* -d '{"sender":"Jane Doe","text":"test","isComment":false,"senderEmail":"dagfinn.parnas@bouvet.no"}'
* http://localhost:8080/feed_stream/api/feed/
*
* @param feedEntry
* @return
*/
@PUT
@Consumes( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response createSingleFeed(FeedEntry feedEntry) {
//The feedEntry is automatically generated based on the input. Yeah!
logger.info("Creating new feed " + feedEntry);
//persist the entry
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(feedEntry);
em.getTransaction().commit();
//The HTTP response should include the URL to the newly generated new entry.
//Probably exist a better way of doing this, but it works
try {
URI createdURI = new URI(uriInfo.getAbsolutePath()+""+ feedEntry.getId());
return Response.created(createdURI).build();
} catch (URISyntaxException e) {
logger.warn("Unable to create correct URI for newly created feed " + feedEntry, e);
//fallback is to include the input path (which will be lacking the id of the new object)
return Response.created(uriInfo.getAbsolutePath()).build();
}
}
/**
* Update one or more fields of a single feed entry
*
* Curl example (updates senderEmail for feed with id 2) :
* $ curl -i -X POST -H 'Content-Type: application/json'
* -d '{"senderEmail":"dagfinn.parnas@gmail.com"}' http://localhost:8080/feed_stream/api/feed/2
*
* @param feedId
* @return The encoded FeedEntry or null if not FeedEntry matches
*/
@POST
@Consumes( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("{feedid}/")
public Response updateSingleFeed(@PathParam("feedid") String strFeedId, FeedEntry modifiedFeedEntry) {
logger.info("updateSingleFeed with id:"+ strFeedId + " called");
try {
long feedId = Long.parseLong(strFeedId);
EntityManager em = emf.createEntityManager();
FeedEntry currentFeedEntry = em.find(FeedEntry.class, feedId);
if(currentFeedEntry==null){
logger.warn("updateSingleFeed failed as " + strFeedId + " does not exist");
return Response.notModified(strFeedId + " does not exist").build();
}
//allow the post to only have one or more fields updated
if(modifiedFeedEntry.getParent()!=null){
currentFeedEntry.setParent(modifiedFeedEntry.getParent());
}
if(modifiedFeedEntry.getSenderEmail()!=null){
currentFeedEntry.setSenderEmail(modifiedFeedEntry.getSenderEmail());
}
if(modifiedFeedEntry.getSenderName()!=null){
currentFeedEntry.setSenderName(modifiedFeedEntry.getSenderName());
}
if(modifiedFeedEntry.getText()!=null){
currentFeedEntry.setText(modifiedFeedEntry.getText());
}
if(modifiedFeedEntry.getTimestamp()!=null){
currentFeedEntry.setTimestamp(modifiedFeedEntry.getTimestamp());
}
//store in persistency store
em.getTransaction().begin();
em.persist(currentFeedEntry);
em.getTransaction().commit();
//return an ok response
return Response.ok().build();
}catch (NumberFormatException e1) {
// TODO: Input parameter is not a long and therefore not a valid primary key
logger.warn("getSingleFeed for " + strFeedId + " is not a valid key", e1);
}catch (IllegalArgumentException e2){
//Invalid type of parameter . Should not happen normally
logger.warn("getSingleFeed for " + strFeedId + " gave exception", e2);
}
return null;
}
/**
* Initialize the persistency layer (JPA)
*
* @throws Exception
*/
private void initPersistencyLayer() throws Exception {
try {
logger.debug("Setting up persistency layer for FeedResource");
InitialContext ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/DefaultDB");
Map properties = new HashMap();
properties.put(PersistenceUnitProperties.NON_JTA_DATASOURCE, ds);
//IMPORTANT! The first parameter must match your JPA Model name in persistence.xml
emf = Persistence.createEntityManagerFactory("FeedModel", properties);
} catch (NamingException e) {
//TODO: Handle exception better
e.printStackTrace();
throw new Exception(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment