How to post multiple files (images) using Jersey Web service.? - java

Hi I am new to Restful web service.
My Goal is to create multiple user account's in a single request.
I am choosing Jersey API to create a web service.
This WS will create multiple user's account. Each user account was associated with an avatar (Profile picture). I am sending the user information with avatar (The avatar file was encoded into string format using Base64 encoder).
My question is, If the request has many number of users, and each user is associated with bigger size of avatar, Is Restful web service can handle these request?
Also the Request data size in the restful webservice is limited?
Please Suggest me to create a better web service in Jersey API.

Instead of passing avatars in message body you should look at Jersey Multipart support - it will allow you to stream large files to your restful service. Another plus - you'll not need Base64 encoding anymore.

I can achieve this by doing form submit instead of preparing the object in JSON format.
#Path("/upload")
public class MultipleFiles
{
private static final String FILE_UPLOAD_PATH = "/Users/arun_kumar/Pictures";
private static final String CANDIDATE_NAME = "candidateName";
private static final String SUCCESS_RESPONSE = "Successful";
private static final String FAILED_RESPONSE = "Failed";
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("text/plain")
#Path("/multipleFiles")
public String registerWebService(#Context HttpServletRequest request)
{
String responseStatus = SUCCESS_RESPONSE;
String candidateName = null;
//checks whether there is a file upload request or not
if (ServletFileUpload.isMultipartContent(request))
{
final FileItemFactory factory = new DiskFileItemFactory();
final ServletFileUpload fileUpload = new ServletFileUpload(factory);
try
{
/*
* parseRequest returns a list of FileItem
* but in old (pre-java5) style
*/
final List items = fileUpload.parseRequest(request);
if (items != null)
{
final Iterator iter = items.iterator();
while (iter.hasNext())
{
final FileItem item = (FileItem) iter.next();
final String itemName = item.getName();
final String fieldName = item.getFieldName();
final String fieldValue = item.getString();
if (item.isFormField())
{
candidateName = fieldValue;
System.out.println(" Name: " + fieldName + ", Value: " + fieldValue);
}
else
{
final File savedFile = new File(FILE_UPLOAD_PATH + File.separator
+ itemName);
System.out.println(" Saving the file: " + savedFile.getName());
item.write(savedFile);
}
}
}
}
catch (FileUploadException fue)
{
responseStatus = FAILED_RESPONSE;
fue.printStackTrace();
}
catch (Exception e)
{
responseStatus = FAILED_RESPONSE;
e.printStackTrace();
}
}
System.out.println("Returned Response Status: " + responseStatus);
return responseStatus;
}
}
Reference: Jersey REST Web Service to Upload Multiple Files

Related

File between backend a front end (full example)

I'm passing a file url to the front end. The problem is that url is only available to the server (settings.dockerIP()) because the user doesn't have connection to the docker.
So I need a way to transform my url into a file and then send it to the user all in the backend..
My current code is like this (it works but the user needs a tunnel to docker host)
Controller
#RequestMapping("/report")
public ModelAndView report(HttpServletRequest request) {
String environmentName = request.getParameter("name");
ModelAndView model = new ModelAndView("report");
model.addObject("file", Report.getFileFromContainer(environmentName));
return model;
}
Class
public static String getFileFromContainer(String environmentName) {
Container container = getContainerID(environmentName);
String url = "";
if(container != null) {
Settings settings = Settings.getSettings();
url = "http://" + settings.getDockerIP() + ":" + settings.getDockerPort() + "/containers/" + container.getId() + "/archive?path=/path/file";
}
return url;
}
Front end
You can create a method in wich your return a file as a stream , the you assign the url of this last to your link button ,
#RequestMapping(value="getFile", method=RequestMethod.GET)
public void getFile(HttpServletResponse response,HttpServletRequest request) {
String environmentName = request.getParameter("name");
//here the code to get your file as stream
//whether getting the file by Ressource or buffred ,
//here for example I named a getfileStream() method wihch return your file InputStream
InputStream myStream = getFileStream(environmentName);
// Set the content type and attachment header add filename and it's extention.
response.addHeader("Content-disposition", "attachment;filename=myfile.myExtention");
response.setContentType("txt/plain");
// copy your file stream to Response
IOUtils.copy(myStream, response.getOutputStream());
response.flushBuffer();
}
in order to get the name parameter you just pass it to the modelview in the /report controller , an then assign it to your link .
As below :
#RequestMapping("/report")
public ModelAndView report(HttpServletRequest request) {
String environmentName = request.getParameter("name");
ModelAndView model = new ModelAndView("report");
model.addObject("name", environmentName);
return model;
}
then your link would be like :
Get file
the getFileStream could be like :
public InputStream getFileStream(String environmentName) {
Container container = getContainerID(environmentName);
String url = "";
if(container != null) {
Settings settings = Settings.getSettings();
url = "http://" + settings.getDockerIP() + ":" + settings.getDockerPort() + "/containers/" + container.getId() + "/archive?path=/path/file";
}
InputStream is = new URL(url).openStream();
return is;
}
You have to add the following appace common io to your project in order to use the IOUtils
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>

Servlet Filter is Returning "Proxy Error" on AWS

I have set up a Filter to add crawler support for my GWT web application. The idea is to catch all requests that contain "_escaped_fragment_=" and supply a snapshot for the crawler.
I have set up the Filter using Guice as follows:
filter("/*").through(CrawlerFilter.class);
The following is the code for the CrawlerFilter class (many thanks to Patrick):
#Singleton
public class CrawlerFilter implements Filter {
private static final Logger logger = Logger.getLogger(CrawlerFilter.class.getName());
/**
* Special URL token that gets passed from the crawler to the servlet
* filter. This token is used in case there are already existing query
* parameters.
*/
private static final String ESCAPED_FRAGMENT_FORMAT1 = "_escaped_fragment_=";
private static final int ESCAPED_FRAGMENT_LENGTH1 = ESCAPED_FRAGMENT_FORMAT1.length();
/**
* Special URL token that gets passed from the crawler to the servlet
* filter. This token is used in case there are not already existing query
* parameters.
*/
private static final String ESCAPED_FRAGMENT_FORMAT2 = "&" + ESCAPED_FRAGMENT_FORMAT1;
private static final int ESCAPED_FRAGMENT_LENGTH2 = ESCAPED_FRAGMENT_FORMAT2.length();
private class SyncAllAjaxController extends NicelyResynchronizingAjaxController {
private static final long serialVersionUID = 1L;
#Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async) {
return true;
}
}
private WebClient webClient = null;
private static final long _pumpEventLoopTimeoutMillis = 30000;
private static final long _jsTimeoutMillis = 1000;
private static final long _pageWaitMillis = 200;
final int _maxLoopChecks = 2;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
ServletException {
// Grab the request uri and query strings.
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final String requestURI = httpRequest.getRequestURI();
final String queryString = httpRequest.getQueryString();
final HttpServletResponse httpResponse = (HttpServletResponse) response;
if ((queryString != null) && (queryString.contains(ESCAPED_FRAGMENT_FORMAT1))) {
// This is a Googlebot crawler request, let's return a static
// indexable html page post javascript execution, as rendered in the browser.
final String domain = httpRequest.getServerName();
final int port = httpRequest.getServerPort();
// Rewrite the URL back to the original #! version
// -- basically remove _escaped_fragment_ from the query.
// Unescape any %XX characters as need be.
final String urlStringWithHashFragment = requestURI + rewriteQueryString(queryString);
final String scheme = httpRequest.getScheme();
final URL urlWithHashFragment = new URL(scheme, "127.0.0.1", port, urlStringWithHashFragment); // get from localhost
final WebRequest webRequest = new WebRequest(urlWithHashFragment);
// Use the headless browser to obtain an HTML snapshot.
webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
webClient.getCache().clear();
webClient.setJavaScriptEnabled(true);
webClient.setThrowExceptionOnScriptError(false);
webClient.setRedirectEnabled(false);
webClient.setAjaxController(new SyncAllAjaxController());
webClient.setCssErrorHandler(new SilentCssErrorHandler());
if (logger.getLevel() == Level.FINEST)
logger.log(Level.FINEST, "HtmlUnit starting webClient.getPage(webRequest) where webRequest = "
+ webRequest.toString());
final HtmlPage page = webClient.getPage(webRequest);
// Important! Give the headless browser enough time to execute
// JavaScript
// The exact time to wait may depend on your application.
webClient.getJavaScriptEngine().pumpEventLoop(_pumpEventLoopTimeoutMillis);
int waitForBackgroundJavaScript = webClient.waitForBackgroundJavaScript(_jsTimeoutMillis);
int loopCount = 0;
while (waitForBackgroundJavaScript > 0 && loopCount < _maxLoopChecks) {
++loopCount;
waitForBackgroundJavaScript = webClient.waitForBackgroundJavaScript(_jsTimeoutMillis);
if (waitForBackgroundJavaScript == 0) {
if (logger.getLevel() == Level.FINEST)
logger.log(Level.FINEST, "HtmlUnit exits background javascript at loop counter " + loopCount);
break;
}
synchronized (page) {
if (logger.getLevel() == Level.FINEST)
logger.log(Level.FINEST, "HtmlUnit waits for background javascript at loop counter "
+ loopCount);
try {
page.wait(_pageWaitMillis);
}
catch (InterruptedException e) {
logger.log(Level.SEVERE, "HtmlUnit ERROR on page.wait at loop counter " + loopCount);
e.printStackTrace();
}
}
}
webClient.getAjaxController().processSynchron(page, webRequest, false);
if (webClient.getJavaScriptEngine().isScriptRunning()) {
logger.log(Level.WARNING, "HtmlUnit webClient.getJavaScriptEngine().shutdownJavaScriptExecutor()");
webClient.getJavaScriptEngine().shutdownJavaScriptExecutor();
}
// Return the static snapshot.
final String staticSnapshotHtml = page.asXml();
httpResponse.setContentType("text/html;charset=UTF-8");
final PrintWriter out = httpResponse.getWriter();
out.println("<hr />");
out.println("<center><h3>This is a non-interactive snapshot for crawlers. Follow <a href=\"");
out.println(urlWithHashFragment + "\">this link</a> for the interactive application.<br></h3></center>");
out.println("<hr />");
out.println(staticSnapshotHtml);
// Close web client.
webClient.closeAllWindows();
out.println("");
out.flush();
out.close();
if (logger.getLevel() == Level.FINEST)
logger.log(Level.FINEST, "HtmlUnit completed webClient.getPage(webRequest) where webRequest = "
+ webRequest.toString());
}
else {
if (requestURI.contains(".nocache.")) {
// Ensure the gwt nocache bootstrapping file is never cached.
// References:
// https://stackoverflow.com/questions/4274053/how-to-clear-cache-in-gwt
// http://seewah.blogspot.com/2009/02/gwt-tips-2-nocachejs-getting-cached-in.html
//
final Date now = new Date();
httpResponse.setDateHeader("Date", now.getTime());
httpResponse.setDateHeader("Expires", now.getTime() - 86400000L); // One day old.
httpResponse.setHeader("Pragma", "no-cache");
httpResponse.setHeader("Cache-control", "no-cache, no-store, must-revalidate");
}
filterChain.doFilter(request, response);
}
}
/**
* Maps from the query string that contains _escaped_fragment_ to one that
* doesn't, but is instead followed by a hash fragment. It also unescapes
* any characters that were escaped by the crawler. If the query string does
* not contain _escaped_fragment_, it is not modified.
*
* #param queryString
* #return A modified query string followed by a hash fragment if
* applicable. The non-modified query string otherwise.
* #throws UnsupportedEncodingException
*/
private static String rewriteQueryString(String queryString) throws UnsupportedEncodingException {
// Seek the escaped fragment.
int index = queryString.indexOf(ESCAPED_FRAGMENT_FORMAT2);
int length = ESCAPED_FRAGMENT_LENGTH2;
if (index == -1) {
index = queryString.indexOf(ESCAPED_FRAGMENT_FORMAT1);
length = ESCAPED_FRAGMENT_LENGTH1;
}
if (index != -1) {
// Found the escaped fragment, so build back the original decoded
// one.
final StringBuilder queryStringSb = new StringBuilder();
// Add url parameters if any.
if (index > 0) {
queryStringSb.append("?");
queryStringSb.append(queryString.substring(0, index));
}
// Add the hash fragment as a replacement for the escaped fragment.
queryStringSb.append("#!");
// Add the decoded token.
final String token2Decode = queryString.substring(index + length, queryString.length());
final String tokenDecoded = URLDecoder.decode(token2Decode, "UTF-8");
queryStringSb.append(tokenDecoded);
return queryStringSb.toString();
}
return queryString;
}
#Override
public void destroy() {
if (webClient != null)
webClient.closeAllWindows();
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
It uses HtmlUnit to create the snapshot.
However; the error occurs when I try to access the snapshot using a regular browser. The URL that I enter is of the form:
http://www.myapp.com/?_escaped_fragment_=myobject%3Bid%3D507ac730e4b0e2b7a73b1b81
But the processing by the Filter results in the following error:
Proxy Error
The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET /.
Reason: Error reading from remote server
Apache/2.2.22 (Amazon) Server at www.myapp.com Port 80
Any help would be appreciated.

Retrieve an Image from a POST request

I am trying to send a picture to my java servlet (hosted on amazon ec2) to later transfer it to amazon s3 and wonder how to retrieve the Image from the post request.
Upload Code
The request is sent through iOS RestKit API like this (pic.imageData is a NSData type):
RKParams* params = [RKParams params];
[params setValue:pic.dateTaken forParam:#"dateTaken"];
[params setValue:pic.dateUploaded forParam:#"dateUploaded"];
[params setData:pic.imageData MIMEType:#"image/jpeg" forParam:#"image"];
[RKClient sharedClient].username = deviceID;
[RKClient sharedClient].password = sessionKey;
[RKClient sharedClient].authenticationType = RKRequestAuthenticationTypeHTTPBasic;
uploadPictureRequest = [[RKClient sharedClient] post:kUploadPictureServlet params:params delegate:self];
Parsing Code Stub
This is how I parse the other 2 parameters on the Java servlet:
double dateTaken = Double.parseDouble(req.getParameter("dateTaken"));
double dateUploaded = Double.parseDouble(req.getParameter("dateUploaded"));
Question
The question is: how do I retrieve and parse the image on my server?
Servlet 3.0 has support for reading multipart data. MutlipartConfig support in Servlet 3.0 If a servelt is annotated using #MutlipartConfig annotation, the container is responsible for making the Multipart parts available through
HttpServletRequest.getParts()
HttpServletRequest.getPart("name");
References:
Servlet 3.0 File Upload handing files and params
Servlet 3.0 File upload Example
Something along the lines of this, using Apache Commons FileUpload:
// or #SuppressWarnings("unchecked")
#SuppressWarnings("rawtypes")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (ServletFileUpload.isMultipartContent(request)) {
final FileItemFactory factory = new DiskFileItemFactory();
final ServletFileUpload upload = new ServletFileUpload(factory);
try {
final List items = upload.parseRequest(request);
for (Iterator itr = items.iterator(); itr.hasNext();) {
final FileItem item = (FileItem) itr.next();
if (!item.isFormField()) {
/*
* TODO: (for you)
* 1. Verify that file item is an image type.
* 2. And do whatever you want with it.
*/
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
Refer to the FileItem API reference doc to determine what to do next.

GWT Facebook Integration

I am trying to write a server side Facebook Notification service in my GWT app. The idea is that I will run this as a timertask or cron job sort of.
With the code below, I get a login URL, I want to be able to Login programmatically as this is intended to be automated (Headless sort of way). I was gonna try do a submit with HTMLunit but I thought the FB API should cater for this.
Please advice.
public class NotificationServiceImpl extends RemoteServiceServlet implements NotificationService {
/**serialVersionUID*/
private static final long serialVersionUID = 6893572879522128833L;
private static final String FACEBOOK_USER_CLIENT = "facebook.user.client";
long facebookUserID;
public String sendMessage(Notification notification) throws IOException {
String api_key = notification.getApi_key();
String secret = notification.getSecret_key();
try {
// MDC.put(ipAddress, req.getRemoteAddr());
HttpServletRequest request = getThreadLocalRequest();
HttpServletResponse response = getThreadLocalResponse();
HttpSession session = getThreadLocalRequest().getSession(true);
// session.setAttribute("api_key", api_key);
IFacebookRestClient<Document> userClient = getUserClient(session);
if(userClient == null) {
System.out.println("User session doesn't have a Facebook API client setup yet. Creating one and storing it in the user's session.");
userClient = new FacebookXmlRestClient(api_key, secret);
session.setAttribute(FACEBOOK_USER_CLIENT, userClient);
}
System.out.println("Creating a FacebookWebappHelper, which copies fb_ request param data into the userClient");
FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(request, response, api_key, secret, userClient);
String nextPage = request.getRequestURI();
nextPage = nextPage.substring(nextPage.indexOf("/", 1) + 1); //cut out the first /, the context path and the 2nd /
System.out.println(nextPage);
boolean redirectOccurred = facebook.requireLogin(nextPage);
if(redirectOccurred) {
return null;
}
redirectOccurred = facebook.requireFrame(nextPage);
if(redirectOccurred) {
return null;
}
try {
facebookUserID = userClient.users_getLoggedInUser();
if (userClient.users_hasAppPermission(Permission.STATUS_UPDATE)) {
userClient.users_setStatus("Im testing Facebook With Java! This status is written using my Java code! Can you see it? Cool :D", false);
}
} catch(FacebookException ex) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while fetching user's facebook ID");
System.out.println("Error while getting cached (supplied by request params) value " +
"of the user's facebook ID or while fetching it from the Facebook service " +
"if the cached value was not present for some reason. Cached value = {}" + userClient.getCacheUserId());
return null;
}
// MDC.put(facebookUserId, String.valueOf(facebookUserID));
// chain.doFilter(request, response);
} finally {
// MDC.remove(ipAddress);
// MDC.remove(facebookUserId);
}
return String.valueOf(facebookUserID);
}
public static FacebookXmlRestClient getUserClient(HttpSession session) {
return (FacebookXmlRestClient)session.getAttribute(FACEBOOK_USER_CLIENT);
}
}
Error message:
[ERROR] com.google.gwt.user.client.rpc.InvocationException: <script type="text/javascript">
[ERROR] top.location.href = "http://www.facebook.com/login.php?v=1.0&api_key=MY_KEY&next=notification";
[ERROR] </script>

Sent request parameters to UploadAction in gwt-upload

I get gwt-upload working in a GAE application. As suggested, I implemented a Custom UploadAction to handle the storage of the file in the DataStore. The code goes like this:
public String executeAction(HttpServletRequest request,
List<FileItem> sessionFiles) throws UploadActionException {
logger.info("Starting: DatastoreUploadAction.executeAction");
String executeAction = super.executeAction(request, sessionFiles);
for (FileItem uploadedFile : sessionFiles) {
Long entityId = new Long(2001); // This is where i wanna use a request parameter
InputStream imgStream;
try {
imgStream = uploadedFile.getInputStream();
Blob attachment = new Blob(IOUtils.toByteArray(imgStream));
String contentType = uploadedFile.getContentType();
appointmentDao.setAppointmentAttachment(entityId, attachment,
contentType);
} catch (IOException e) {
logger.error("Unable to store file", e);
throw new UploadActionException(e);
}
}
return executeAction;
}
As you see, the DAO class requires the "EntityID" to store the uploaded file in the DataStore. Now i'm working with a hard-coded value and it goes fine, but i'd like to have the entityID sent by the client as a request parameter. The widget that does the upload is a MultiUploader:
private MultiUploader defaultUploader;
Is it posible to the MultiUploader -or any other Widget- to set a request parameter so i can use it in my UploadAction?
Yes, you can set it on your client-side code. There is method: MultiUploader #setServletPath(java.lang.String), for example:
final MultiUploader u = new MultiUploader();
...
...
...
u.setServletPath(u.getServletPath() + "?entityId="+myObject.getEntityId());
on server side:
String entityId= request.getParameter("entityId");
Read this for more information: Sending additional parameters to the servlet

Categories