Beispiel #1
0
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String blobKey = req.getParameter("blobKey");
    String path = req.getParameter("path");

    if (path != null && path.trim().length() > 0) {
      JsonObject retObj = new JsonObject();

      String uploadBlobPath =
          BlobstoreServiceFactory.getBlobstoreService()
              .createUploadUrl(URLDecoder.decode(path), UploadOptions.Builder.withDefaults());

      retObj.addProperty("result", "success");
      retObj.addProperty("path", URLEncoder.encode(uploadBlobPath));

      if (retObj.get("result") == null) {
        retObj.addProperty("result", "fail");
      }

      resp.getWriter().write(retObj.toString());
    } else if (blobKey != null) {
      BlobstoreServiceFactory.getBlobstoreService().serve(new BlobKey(blobKey), resp);
    }
  }
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ServletException {
    String path = request.getPathInfo();
    List<StaticFile> staticFiles = new ArrayList<StaticFile>();

    if (path.endsWith("/all")) {
      staticFiles.addAll(StaticFile.all().order("name").fetch());
    } else {
      StaticFile file = StaticFile.all().filter("path", removeLeadingSlash(path)).get();
      if (file != null) {
        staticFiles.add(file);
      }
    }

    // no caching of json

    for (StaticFile file : staticFiles) {
      byte[] fileData =
          BlobstoreServiceFactory.getBlobstoreService()
              .fetchData(
                  new BlobKey(file.getBlobKey()), 0, BlobstoreService.MAX_BLOB_FETCH_SIZE - 1);
      String base64fileData = Base64.encodeBase64URLSafeString(fileData); // UTF-8, JSON-safe
      file.setData(base64fileData);
    }

    response.setContentType("application/json");
    response.setStatus(200);
    PrintWriter out = response.getWriter();
    out.print(new JsonResponse(staticFiles).toJson());
  }
  @InSequence(10)
  @Test
  @OperateOnDeployment("dep1")
  public void insertIntoBlobstoreOnDep1() throws Exception {
    BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();

    FileService fileService = FileServiceFactory.getFileService();
    AppEngineFile file = fileService.createNewBlobFile("text/plain", "uploadedText.txt");
    FileWriteChannel channel = fileService.openWriteChannel(file, true);
    try {
      channel.write(ByteBuffer.wrap(TEXT.getBytes()));
    } finally {
      channel.closeFinally();
    }

    waitForSync();
    BlobKey blobKey = fileService.getBlobKey(file);
    System.out.println("Blob key: " + blobKey);
    byte[] bytes = service.fetchData(blobKey, 0, Long.MAX_VALUE);

    Assert.assertEquals(TEXT, new String(bytes));

    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    Entity dsBK = new Entity("blobTestId", 1);
    dsBK.setProperty("blogId", blobKey.getKeyString());
    ds.put(dsBK);
    waitForSync();
  }
/**
 * A Controller version that contains utilities methods to handler the GAE Blobstore facilities.
 *
 * @author Danilo Queiroz - [email protected]
 */
public abstract class BlobstoreController extends Controller {

  private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

  /**
   * Gets the blobservice upload url.
   *
   * @param successPath The url to blobservice redirect after a successful upload.
   * @return the blobservice upload url.
   */
  protected final String uploadUrl(String successPath) {
    return this.blobstoreService.createUploadUrl(successPath);
  }

  /**
   * Gets the {@link BlobKey} a uploaded file.
   *
   * @param file the uploaded file's name - the name used by the form to define the file
   * @return The {@link BlobKey} fot the given file, or <code>null</code> if there's no file
   *     uploaded with the given name
   * @throws IllegalStateException If not called from a blob upload callback request.
   */
  protected final BlobKey blobKey(String file) {
    return this.blobstoreService.getUploadedBlobs(this.request()).get(file);
  }

  /**
   * Serves a file with the given {@link BlobKey}
   *
   * @param blobKey the file's {@link BlobKey}
   */
  protected final void serve(String blobKey) {
    this.setControllerResponse(new BlobResponse(blobstoreService, new BlobKey(blobKey)));
  }
}
public class BlobStoreServletWithExternalUrl extends HttpServlet {
  private static final Logger log =
      Logger.getLogger(BlobStoreServletWithExternalUrl.class.getName());

  private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

  public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    res.setHeader("Cache-Control", "max-age=2592000");
    BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
    blobstoreService.serve(blobKey, res);
  }

  protected void doPost(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    try {
      Long runId = null;
      String account = null;
      String fileName = null;
      runId = Long.parseLong(req.getParameter("runId"));
      account = req.getParameter("account");
      fileName = req.getParameter("fileName");
      if (req.getParameter("withBlob") == null) {
        //                UploadOptions uploadOptions =
        // UploadOptions.Builder.withGoogleStorageBucketName("streetlearn"); //TODO this was added

        String uploadUrl =
            blobstoreService.createUploadUrl(
                "/uploadServiceWithUrl?withBlob=true&runId="
                    + runId
                    + "&account="
                    + account
                    + "&fileName="
                    + fileName); // TODO this was the old one
        //                String uploadUrl =
        // blobstoreService.createUploadUrl("/uploadServiceWithUrl?withBlob=true&runId=" + runId +
        // "&account=" + account + "&fileName=" + fileName, uploadOptions);
        res.getWriter().write(uploadUrl);

      } else {

        //                GcsService gcsService = GcsServiceFactory.createGcsService(new
        // RetryParams.Builder()
        //                        .initialRetryDelayMillis(10)
        //                        .retryMaxAttempts(10)
        //                        .totalRetryPeriodMillis(15000)
        //                        .build());

        java.util.Map<java.lang.String, java.util.List<BlobKey>> blobs =
            blobstoreService.getUploads(req);
        for (String key : blobs.keySet()) {
          FilePathManager.addFile(runId, account, fileName, blobs.get(key).get(0));
        }
      }

    } catch (Exception ex) {
      throw new ServletException(ex);
    }
  }
}
Beispiel #6
0
  @Override
  protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String blobKey = req.getParameter("blobKey");
    JsonObject retObj = new JsonObject();

    if (blobKey != null) {
      BlobstoreServiceFactory.getBlobstoreService().delete(new BlobKey(blobKey));
      retObj.addProperty("result", "success");
    }

    if (retObj.get("result") == null) {
      retObj.addProperty("result", "fail");
    }

    resp.getWriter().write(retObj.toString());
  }
  private static BlobKey getBlobkKey(ImageRef ref) {
    ImageStore store = new ImageStore();
    store.init();

    Optional<StoredImage> image = store.tryLoadImage(ref);
    if (image.isPresent()) {
      log.info("Using blobkey: " + image.get().getBlobKey());
      return new BlobKey(image.get().getBlobKey());
    } else {
      GcsFilename oldGcsFileName = createOldGcsFileName(ref.getReportId(), ref.getImageName());
      log.info("Using old GCS fileName: " + oldGcsFileName.toString());

      BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
      // Does not work on dev server.
      return blobstoreService.createGsBlobKey(
          "/gs/" + oldGcsFileName.getBucketName() + "/" + oldGcsFileName.getObjectName());
    }
  }
 private void remove(String encoded, HttpServletResponse response) throws IOException {
   BlobstoreService blobstore = BlobstoreServiceFactory.getBlobstoreService();
   DatastoreService datastore = DS.get();
   Key key = KeyFactory.stringToKey(encoded);
   Transaction tr = datastore.beginTransaction();
   try {
     Entity blog = datastore.get(key);
     datastore.delete(key);
     response.setContentType("text/plain");
     PrintWriter writer = response.getWriter();
     writer.println("Deleted blog: " + blog.getProperty("Subject"));
     tr.commit();
   } catch (EntityNotFoundException ex) {
     throw new IOException(ex);
   } finally {
     if (tr.isActive()) {
       tr.rollback();
     }
   }
 }
Beispiel #9
0
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();
    Map<String, List<BlobKey>> blobs = bs.getUploads(req);
    List<BlobKey> imageBlobs = blobs.get("source");

    JsonObject retObj = new JsonObject();

    if (imageBlobs.size() > 0) {
      BlobKey image = imageBlobs.get(0);
      retObj.addProperty("result", "success");
      retObj.addProperty("blobKey", image.getKeyString());
    }

    if (retObj.get("result") == null) {
      retObj.addProperty("result", "fail");
    }

    resp.getWriter().write(retObj.toString());
  }
  @InSequence(20)
  @Test
  @OperateOnDeployment("dep2")
  public void readFromBlobstoreOnDep2() throws Exception {
    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    Key key = KeyFactory.createKey("blobTestId", 1);
    Entity dsBK = ds.get(key);
    String blobKeyStr = (String) dsBK.getProperty("blogId");
    BlobKey blobKey = new BlobKey(blobKeyStr);
    if (blobKeyStr == null || blobKeyStr.equals("")) {
      fail("Datastore should have this value. Try to run clustered DatastoreTestCase first.");
    }

    BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
    System.out.println("Blob key: " + blobKey);
    byte[] bytes = service.fetchData(blobKey, 0, Long.MAX_VALUE);
    try {
      Assert.assertEquals(TEXT, new String(bytes));
    } finally {
      service.delete(blobKey);
    }
  }
 private Future<HTTPResponse> postBlobs(
     String filename,
     String contentType,
     String sha1,
     byte[] data,
     String metadataSize,
     HttpServletRequest request,
     int width,
     int height)
     throws MessagingException, IOException {
   try {
     URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
     BlobstoreService blobstore = BlobstoreServiceFactory.getBlobstoreService();
     URI reqUri = new URI(request.getScheme(), request.getServerName(), "", "");
     URI uri =
         reqUri.resolve(
             "/blob?"
                 + NamespaceParameter
                 + "="
                 + NamespaceManager.get()
                 + "&"
                 + SizeParameter
                 + "="
                 + metadataSize
                 + "&"
                 + WidthParameter
                 + "="
                 + width
                 + "&"
                 + HeightParameter
                 + "="
                 + height);
     URL uploadUrl = new URL(blobstore.createUploadUrl(uri.toASCIIString()));
     log("post blob to " + uploadUrl);
     HTTPRequest httpRequest =
         new HTTPRequest(uploadUrl, HTTPMethod.POST, FetchOptions.Builder.withDeadline(60));
     String uid = UUID.randomUUID().toString();
     httpRequest.addHeader(new HTTPHeader("Content-Type", "multipart/form-data; boundary=" + uid));
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     PrintStream ps = new PrintStream(baos);
     ps.append("--" + uid);
     ps.append(CRLF);
     ps.append(
         "Content-Disposition: form-data; name=\"" + sha1 + "\"; filename=\"" + filename + "\"");
     ps.append(CRLF);
     ps.append("Content-Type: " + contentType);
     ps.append(CRLF);
     ps.append("Content-Transfer-Encoding: binary");
     ps.append(CRLF);
     ps.append(CRLF);
     ps.write(data);
     ps.append(CRLF);
     ps.append("--" + uid + "--");
     ps.append(CRLF);
     ps.close();
     log("sending blob size=" + baos.size());
     httpRequest.setPayload(baos.toByteArray());
     return fetchService.fetchAsync(httpRequest);
   } catch (URISyntaxException ex) {
     throw new IOException(ex);
   }
 }
Beispiel #12
0
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    int index;

    DatastoreService ds;
    MemcacheService ms;
    BlobstoreService bs;
    URLFetchService us;
    FileService fs;

    Map<String, List<BlobKey>> blobMap;
    BlobKey blobKey;
    BlobInfoFactory blobInfoFactory;
    BlobInfo blobInfo;

    int postCount;
    int postIndex;
    String postType;
    String postText;
    String postDelpw;
    String postShowgallery;
    DataObj dataObj;
    String filelink;

    String picUrl;
    HTTPResponse picRes;
    List<HTTPHeader> headerList;
    String picMime;
    String[] fileNamePart;
    AppEngineFile picFile;
    FileWriteChannel writeChannel;

    PostObj postObj;
    List<PostObj> postObjList;
    String linkID;

    resp.setCharacterEncoding("UTF-8");
    resp.setContentType("text/plain");

    try {
      ds = DatastoreServiceFactory.getDatastoreService();
      ms = MemcacheServiceFactory.getMemcacheService();
      bs = BlobstoreServiceFactory.getBlobstoreService();
      us = URLFetchServiceFactory.getURLFetchService();
      fs = FileServiceFactory.getFileService();
      blobInfoFactory = new BlobInfoFactory(ds);

      blobMap = bs.getUploads(req);
      postCount = Integer.valueOf(req.getParameter("input_post_count"));
      postObjList = new ArrayList<PostObj>();

      for (postIndex = 0; postIndex < postCount; postIndex++) {
        try {
          postType = req.getParameter("input_post_type_" + postIndex);
          if (postType == null) {
            continue;
          }

          postText = req.getParameter("input_post_text_" + postIndex);
          postDelpw = req.getParameter("input_post_delpw_" + postIndex);
          postShowgallery = req.getParameter("input_post_showgallery_" + postIndex);
          if (postShowgallery == null) {
            postShowgallery = "";
          }

          if (postType.equals("file") == true) {
            blobKey = blobMap.get("input_post_file_" + postIndex).get(0);
            if (blobKey == null) {
              throw new Exception();
            }

            dataObj = new DataObj();
            dataObj.fileid = createUID();
            dataObj.posttime = new Date().getTime();
            dataObj.delpw = postDelpw;
            dataObj.blobkey = blobKey;
            dataObj.putDB(ds);

            blobInfo = blobInfoFactory.loadBlobInfo(dataObj.blobkey);
            filelink =
                "http://"
                    + req.getServerName()
                    + "/down/"
                    + dataObj.fileid
                    + "/"
                    + blobInfo.getFilename();
            postObj =
                new PostObj(
                    dataObj.fileid,
                    filelink,
                    blobInfo.getSize(),
                    dataObj.posttime,
                    dataObj.delpw,
                    postShowgallery);
            postObjList.add(postObj);
          } else if (postType.equals("url") == true) {
            picUrl = postText;

            picRes = us.fetch(new URL(picUrl));
            headerList = picRes.getHeaders();
            picMime = "application/octet-stream";
            for (index = 0; index < headerList.size(); index++) {
              if (headerList.get(index).getName().compareToIgnoreCase("Content-Type") == 0) {
                picMime = headerList.get(index).getValue();
                break;
              }
            }

            fileNamePart = picUrl.split("/");

            picFile = fs.createNewBlobFile(picMime, fileNamePart[fileNamePart.length - 1]);
            writeChannel = fs.openWriteChannel(picFile, true);
            writeChannel.write(ByteBuffer.wrap(picRes.getContent()));
            writeChannel.closeFinally();

            dataObj = new DataObj();
            dataObj.fileid = createUID();
            dataObj.posttime = new Date().getTime();
            dataObj.delpw = postDelpw;
            dataObj.blobkey = fs.getBlobKey(picFile);
            dataObj.putDB(ds);

            blobInfo = blobInfoFactory.loadBlobInfo(dataObj.blobkey);
            filelink =
                "http://"
                    + req.getServerName()
                    + "/down/"
                    + dataObj.fileid
                    + "/"
                    + blobInfo.getFilename();
            postObj =
                new PostObj(
                    dataObj.fileid,
                    filelink,
                    blobInfo.getSize(),
                    dataObj.posttime,
                    dataObj.delpw,
                    postShowgallery);
            postObjList.add(postObj);
          }
        } catch (Exception e) {
        }
      }

      linkID = postFile(us, postObjList);

      if (req.getParameter("specflag") != null) {
        resp.getWriter().print("http://tnfshmoe.appspot.com/link.jsp?linkid=" + linkID);
      } else {
        resp.sendRedirect("http://tnfshmoe.appspot.com/link.jsp?linkid=" + linkID);
      }
    } catch (Exception e) {
    }
  }
Beispiel #13
0
public class FileContent extends HttpServlet {
  private BlobstoreService bService = BlobstoreServiceFactory.getBlobstoreService();

  public void doPost(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    String fileName = null;
    long startTime, endTime;
    String fileContentToDisplay = req.getParameter("FileToDisplay");
    res.getWriter().println("File conetent to be displayed : " + fileContentToDisplay);
    startTime = System.currentTimeMillis();
    // Find if the file is in memcache. If present there is no need to go to blobstore to get the
    // data
    MemcacheService mService = MemcacheServiceFactory.getMemcacheService();
    AppEngineFile readableFile;
    readableFile = (AppEngineFile) mService.get(fileName);

    if (readableFile != null) {
      FileService fService = FileServiceFactory.getFileService();
      res.getWriter().println("File " + fileName + " is present in cache");
      FileReadChannel readChannel = fService.openReadChannel(readableFile, false);
      BufferedReader reader = new BufferedReader(Channels.newReader(readChannel, "UTF8"));
      String line = null;
      res.getWriter().println("Contents of the file: ");

      while ((line = reader.readLine()) != null) {
        res.getWriter().println(line + "<br>");
      }
      readChannel.close();
    } else // Search for the file in blob
    {
      List<BlobInfo> blobToRead = new LinkedList<BlobInfo>();
      Iterator<BlobInfo> blobIterator = new BlobInfoFactory().queryBlobInfos();
      while (blobIterator.hasNext()) blobToRead.add(blobIterator.next());
      res.setContentType("text/plain");
      Boolean filePresent = false;
      int i;
      for (i = 0; i < blobToRead.size(); i++) {
        fileName = blobToRead.get(i).getFilename();
        if (fileName.equals(fileContentToDisplay)) {
          FileService fService = FileServiceFactory.getFileService();
          res.getWriter().println("File " + fileName + " is present in the blob store");

          readableFile = fService.getBlobFile(blobToRead.get(i).getBlobKey());

          FileReadChannel readChannel = fService.openReadChannel(readableFile, false);
          BufferedReader reader = new BufferedReader(Channels.newReader(readChannel, "UTF8"));
          String line = null;
          res.getWriter().println("printing the contents : ");

          while ((line = reader.readLine()) != null) {

            res.getWriter().println(line);
          }

          readChannel.close();
        } else {
          res.getWriter().println("File " + fileName + " is not present in the blob store");
        }
      }
    }
    endTime = System.currentTimeMillis();
    res.getWriter().println("Time taken for the operation is " + (endTime - startTime) + " ms");
  }
}
/**
 * Provides an API for working with Photos. This servlet provides the /api/photos endpoint, and
 * exposes the following operations:
 *
 * <p>GET /api/photos GET /api/photos?photoId=1234 GET /api/photos?themeId=1234 GET
 * /api/photos?userId=me GET /api/photos?themeId=1234&userId=me GET
 * /api/photos?themeId=1234&userId=me&friends=true POST /api/photos DELETE /api/photos?photoId=1234
 *
 * @author [email protected] (Vic Fryzel)
 */
public class PhotosServlet extends JsonRestServlet {

  /** Base URL of the /api/photos end-point. Initialized for every GET request. */
  public static String BASE_URL;

  /** BlobstoreService from which to fetch image information after an Image upload. */
  private final BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

  /**
   * Exposed as `GET /api/photos`.
   *
   * <p>Accepts the following request parameters.
   *
   * <p>'photoId': id of the requested photo. Will return a single Photo. 'themeId': id of a theme.
   * Will return the collection of photos for the specified theme. 'userId': id of the owner of the
   * photo. Will return the collection of photos for that user. The keyword ‘me’ can be used and
   * will be converted to the logged in user. Requires auth. 'friends': value evaluated to boolean,
   * if true will filter only photos from friends of the logged in user. Requires auth.
   *
   * <p>Returns the following JSON response representing a list of Photos.
   *
   * <p>[ { "id":0, "ownerUserId":0, "ownerDisplayName":"", "ownerProfileUrl":"",
   * "ownerProfilePhoto":"", "themeId":0, "themeDisplayName":"", "numVotes":0, "voted":false, //
   * Whether or not the current user has voted on this. "created":0, "fullsizeUrl":"",
   * "thumbnailUrl":"", "voteCtaUrl":"", // URL for Vote interactive post button.
   * "photoContentUrl":"" // URL for Google crawler to hit to get info. }, ... ]
   *
   * <p>Issues the following errors along with corresponding HTTP response codes: 401: "Unauthorized
   * request" (if certain parameters are present in the request)
   *
   * @see javax.servlet.http.HttpServlet#doGet( javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
    try {
      BASE_URL = getBaseUrlFromRequest(req);
      String photoId = req.getParameter("photoId");
      String themeId = req.getParameter("themeId");
      String userIdParam = req.getParameter("userId");
      Long userId;
      Long currentUserId = null;
      if (req.getSession().getAttribute(CURRENT_USER_SESSION_KEY) != null) {
        currentUserId =
            Long.parseLong(req.getSession().getAttribute(CURRENT_USER_SESSION_KEY).toString());
      }
      boolean showFriends = Boolean.parseBoolean(req.getParameter("friends"));
      Query<Photo> q = ofy().load().type(Photo.class);
      if (photoId != null) {
        // Get the photo with the given ID and return it.
        Photo photo = q.filter("id", Long.parseLong(photoId)).first().get();
        sendResponse(req, resp, photo);
      } else {
        if (userIdParam != null) {
          // If the key word me is used, retrieve the current user from the session
          // The user needs to be authenticated to use 'me'
          if (userIdParam.equals("me")) {
            checkAuthorization(req);
            userId = currentUserId;
          } else {
            userId = Long.parseLong(userIdParam);
          }
          if (showFriends) {
            checkAuthorization(req);
            // Get all photos for the user's friends.
            User user = ofy().load().type(User.class).filterKey(User.key(userId)).first().get();
            List<Long> friendIds = user.getFriendIds();
            if (friendIds.size() > 30) {
              friendIds = friendIds.subList(0, 30);
            }
            if (friendIds.size() > 0) {
              q = q.filter("ownerUserId in", friendIds);
            } else {
              List<Photo> emptyList = new ArrayList<Photo>();
              // If there are no friends for the user, return an empty list
              sendResponse(req, resp, emptyList, "photohunt#photos");
              return;
            }
          } else {
            // Get all photos for the user.
            q = q.filter("ownerUserId", userId);
          }
        }
        if (themeId != null) {
          // Limit photos to just those for the given theme.
          q = q.filter("themeId", Long.parseLong(themeId));
        }
        List<Photo> photos = q.list();

        if (currentUserId != null) {
          // Build Hash map of voted photos
          List<Vote> userVotes =
              ofy().load().type(Vote.class).filter("ownerUserId", currentUserId).list();
          HashMap<Long, Boolean> userVotesTable = new HashMap<Long, Boolean>(userVotes.size());
          Iterator<Vote> votesIterator = userVotes.iterator();
          while (votesIterator.hasNext()) {
            userVotesTable.put(votesIterator.next().getPhotoId(), true);
          }
          // Check if user voted for each photo
          Iterator<Photo> photosIterator = photos.iterator();
          while (photosIterator.hasNext()) {
            Photo current = photosIterator.next();
            current.setVoted(userVotesTable.containsKey(current.getId()));
          }
        }
        sendResponse(req, resp, photos, "photohunt#photos");
      }
    } catch (UserNotAuthorizedException e) {
      sendError(resp, 401, "Unauthorized request");
    }
  }

  /**
   * Exposed as `POST /api/photos`.
   *
   * <p>Takes the following payload in the request body. Payload represents a Photo that should be
   * created. { "id":0, "ownerUserId":0, "ownerDisplayName":"", "ownerProfileUrl":"",
   * "ownerProfilePhoto":"", "themeId":0, "themeDisplayName":"", "numVotes":0, "voted":false, //
   * Whether or not the current user has voted on this. "created":0, "fullsizeUrl":"",
   * "thumbnailUrl":"", "voteCtaUrl":"", // URL for Vote interactive post button.
   * "photoContentUrl":"" // URL for Google crawler to hit to get info. }
   *
   * <p>Returns the following JSON response representing the created Photo. { "id":0,
   * "ownerUserId":0, "ownerDisplayName":"", "ownerProfileUrl":"", "ownerProfilePhoto":"",
   * "themeId":0, "themeDisplayName":"", "numVotes":0, "voted":false, // Whether or not the current
   * user has voted on this. "created":0, "fullsizeUrl":"", "thumbnailUrl":"", "voteCtaUrl":"", //
   * URL for Vote interactive post button. "photoContentUrl":"" // URL for Google crawler to hit to
   * get info. }
   *
   * <p>Issues the following errors along with corresponding HTTP response codes: 400: "Bad Request"
   * if the request is missing image data. 401: "Unauthorized request" (if certain parameters are
   * present in the request) 401: "Access token expired" (there is a logged in user, but he doesn't
   * have a refresh token and his access token is expiring in less than 100 seconds, get a new token
   * and retry) 500: "Error while writing app activity: " + error from client library.
   *
   * @see javax.servlet.http.HttpServlet#doPost( javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
    try {
      checkAuthorization(req);
      List<BlobKey> blobKeys = blobstoreService.getUploads(req).get("image");
      BlobKey imageKey = null;

      if (blobKeys != null) {
        imageKey = blobKeys.iterator().next();
      }

      if (imageKey == null) {
        sendError(resp, 400, "Missing image data.");
      }

      Long currentUserId = (Long) req.getSession().getAttribute(CURRENT_USER_SESSION_KEY);
      User author = ofy().load().type(User.class).id(currentUserId).get();
      GoogleCredential credential = this.getCredentialFromLoggedInUser(req);
      Photo photo = new Photo();
      photo.setOwnerUserId(author.getId());
      photo.setOwnerDisplayName(author.getGoogleDisplayName());
      photo.setOwnerProfilePhoto(author.getGooglePublicProfilePhotoUrl());
      photo.setOwnerProfileUrl(author.getGooglePublicProfileUrl());
      photo.setThemeId(Theme.getCurrentTheme().getId());
      photo.setThemeDisplayName(Theme.getCurrentTheme().getDisplayName());
      photo.setCreated(Calendar.getInstance().getTime());
      photo.setNumVotes(0);
      photo.setImageBlobKey(imageKey.getKeyString());
      ofy().save().entity(photo).now();
      ofy().clear();
      photo = ofy().load().type(Photo.class).id(photo.getId()).get();
      addPhotoToGooglePlusHistory(author, photo, credential);
      sendResponse(req, resp, photo);
    } catch (UserNotAuthorizedException e) {
      sendError(resp, 401, "Unauthorized request");
    } catch (MomentWritingException e) {
      sendError(resp, 500, "Error while writing app activity: " + e.getMessage());
    } catch (GoogleTokenExpirationException e) {
      sendError(resp, 401, "Access token expired");
    }
  }

  /**
   * Exposed as `DELETE /api/photos`.
   *
   * <p>Accepts the following request parameters.
   *
   * <p>'photoId': id of the photo to delete.
   *
   * <p>Returns the following JSON response representing success. "Photo successfully deleted."
   *
   * <p>Issues the following errors along with corresponding HTTP response codes: 401: "Unauthorized
   * request" (if certain parameters are present in the request) 404: "Photo with given ID does not
   * exist."
   *
   * @see javax.servlet.http.HttpServlet#doDelete( javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {
    final String doesNotExist = "Photo with given ID does not exist.";
    try {
      checkAuthorization(req);
      Long photoId = Long.parseLong(req.getParameter("photoId"));
      Photo photo = ofy().load().key(Photo.key(photoId)).safeGet();
      Long userId =
          Long.parseLong(req.getSession().getAttribute(CURRENT_USER_SESSION_KEY).toString());
      if (!userId.equals(photo.getOwnerUserId())) {
        throw new NotFoundException();
      }
      ofy().delete().entity(photo).now();
      List<Vote> photoVotes = ofy().load().type(Vote.class).filter("photoId", photoId).list();
      ofy().delete().entities(photoVotes);
      sendResponse(req, resp, new Message("Photo successfully deleted"), "photohunt#message");
    } catch (NotFoundException nfe) {
      sendError(resp, 404, doesNotExist);
    } catch (NumberFormatException e) {
      sendError(resp, 404, doesNotExist);
    } catch (UserNotAuthorizedException e) {
      sendError(resp, 401, "Unauthorized request");
    }
  }

  /**
   * Creates an app activity in Google indicating that the given User has uploaded the given Photo.
   *
   * @param author Creator of Photo.
   * @param photo Photo itself.
   * @param credential Credential with which to authorize request to Google.
   * @throws MomentWritingException Failed to write app activity.
   */
  private void addPhotoToGooglePlusHistory(User author, Photo photo, GoogleCredential credential)
      throws MomentWritingException {
    ItemScope target = new ItemScope().setUrl(photo.getPhotoContentUrl());
    Moment content =
        new Moment().setType("http://schemas.google.com/AddActivity").setTarget(target);
    Plus plus = new Plus.Builder(TRANSPORT, JSON_FACTORY, credential).build();
    try {
      Insert request = plus.moments().insert(author.googleUserId, "vault", content);
      Moment moment = request.execute();
    } catch (IOException e) {
      throw new MomentWritingException(e.getMessage());
    }
  }

  /**
   * @param req Request from which to fetch base URL.
   * @return Base URL from the given request.
   */
  private String getBaseUrlFromRequest(HttpServletRequest req) {
    return req.getScheme()
        + "://"
        + req.getServerName()
        + ((req.getServerPort() != 80) ? (":" + req.getServerPort()) : "");
  }

  /** Thrown when writing app activity to Google fails. */
  public static class MomentWritingException extends Exception {
    public MomentWritingException(String message) {
      super(message);
    }
  }
}
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {

    if (DEBUG) System.out.println("an ajax call was made!");

    boolean namesAdded = false;
    StringBuilder sb = new StringBuilder();
    int maxResults = 10;
    double maxDistance = 0.0; // meters // using 0 will return all distances up to max # of results

    double lat = 0.0;
    double lng = 0.0;

    String callType = req.getParameter("callType");
    String cuisine = req.getParameter("cuisineID");
    String category = req.getParameter("categoryID");
    String price = req.getParameter("priceID");
    String lifestyle = req.getParameter("lifestyleID");
    String distanceS = req.getParameter("distance");
    String pageNumS = req.getParameter("page");

    // lat = Double.parseDouble(req.getParameter("lat"));
    // lng = Double.parseDouble(req.getParameter("lng"));
    String distString = req.getParameter("distance");
    if (null != distString && distString.length() > 0) maxDistance = Integer.parseInt(distString);
    maxResults = Integer.parseInt(req.getParameter("maxResults"));
    Point userLoc = TDUserService.getUserLocation(req);
    // TDPoint tdpoint=TDUserService.getUserLocation(req);
    lat = userLoc.getLat();
    lng = userLoc.getLon();

    long priceID = 0;
    long categoryID = 0;
    long lifestyleID = 0;
    long cuisineID = 0;
    int pageNum = 0;

    try {
      priceID = Long.parseLong(price);

      if (DEBUG) System.out.println("price found: " + priceID);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }
    try {
      cuisineID = Long.parseLong(cuisine);

      if (DEBUG) System.out.println("cuisine found: " + cuisineID);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }
    try {
      categoryID = Long.parseLong(category);

      if (DEBUG) System.out.println("category found: " + categoryID);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }
    try {
      maxDistance = Double.parseDouble(distanceS);

      if (DEBUG) System.out.println("distance found: " + maxDistance);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }
    try {
      lifestyleID = Long.parseLong(lifestyle);

      if (DEBUG) System.out.println("lifestyle found: " + lifestyleID);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }
    try {
      pageNum = Integer.parseInt(pageNumS);

      if (DEBUG) System.out.println("page number found: " + pageNum);
    } catch (NumberFormatException e) {
      // not a long
      // e.printStackTrace();
    }

    // compute distance from miles to meters
    maxDistance *= 1609.334;

    Tag categoryTag = null;
    Tag priceTag = null;
    Tag lifestyleTag = null;
    Tag cuisineTag = null;
    ArrayList<Key> tagKeysToFilter = new ArrayList<Key>();

    if (category != null && !category.equals("")) {
      categoryTag = (Tag) PMF.get().getPersistenceManager().getObjectById(Tag.class, categoryID);
      tagKeysToFilter.add(categoryTag.getKey());
    }

    if (price != null && !price.equals("")) {
      priceTag = (Tag) PMF.get().getPersistenceManager().getObjectById(Tag.class, priceID);
      tagKeysToFilter.add(priceTag.getKey());
    }

    if (lifestyle != null && !lifestyle.equals("")) {
      lifestyleTag = (Tag) PMF.get().getPersistenceManager().getObjectById(Tag.class, lifestyleID);
      tagKeysToFilter.add(lifestyleTag.getKey());
    }
    if (cuisine != null && !cuisine.equals("")) {
      cuisineTag = (Tag) PMF.get().getPersistenceManager().getObjectById(Tag.class, cuisineID);
      tagKeysToFilter.add(cuisineTag.getKey());
    }

    List<Dish> dishResults = null;

    if (null != callType && callType.equals("search")) {
      String query = req.getParameter("searchWord");
      if (query.isEmpty()) query = " ";

      query = query.toLowerCase();
      String[] qWords = query.split(" ");

      dishResults =
          TDQueryUtils.searchGeoItemsWithFilter(
              qWords,
              userLoc,
              maxResults,
              maxDistance,
              new Dish(),
              pageNum * maxResults,
              tagKeysToFilter,
              new DishPosReviewsComparator());
    } else {
      dishResults =
          AbstractSearch.filterDishes(
              PMF.get().getPersistenceManager(),
              maxResults,
              tagKeysToFilter,
              maxDistance,
              lat,
              lng,
              pageNum * maxResults,
              new DishPosReviewsComparator());
    }

    if (null != dishResults && dishResults.size() > 0) {
      if (DEBUG) System.out.println("result set size: " + dishResults.size());

      sb.append("<DishSearch>");
      sb.append("<count>" + pageNum + "</count>");
      sb.append("<Dishes>");
      namesAdded = true;
      for (Dish dish : dishResults) {
        Restaurant r =
            PMF.get().getPersistenceManager().getObjectById(Restaurant.class, dish.getRestaurant());
        List<Tag> tags = TDQueryUtils.getAll(dish.getTags(), new Tag());
        Photo dishPhoto = null;

        if (dish.getPhotos() != null && dish.getPhotos().size() > 0) {
          dishPhoto =
              PMF.get().getPersistenceManager().getObjectById(Photo.class, dish.getPhotos().get(0));
        }

        int vote = 0;
        try {
          if (TDUserService.getUserLoggedIn())
            vote =
                TDUserService.getUserVote(
                    TDUserService.getUser(PMF.get().getPersistenceManager()).getKey(),
                    dish.getKey());
        } catch (UserNotLoggedInException e) {
          // e.printStackTrace();
        } catch (UserNotFoundException e) {
          // e.printStackTrace();
        }

        BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
        String blobUploadURL = blobstoreService.createUploadUrl("/addReview");

        sb.append("<Dish>");
        sb.append("<blobUploadURL>" + blobUploadURL + "</blobUploadURL>");
        sb.append("<keyId>" + dish.getKey().getId() + "</keyId>");
        sb.append("<name>" + StringEscapeUtils.escapeHtml(dish.getName()) + "</name>");
        sb.append(
            "<description>"
                + StringEscapeUtils.escapeHtml(dish.getDescription())
                + "</description>");
        sb.append(
            "<distance>"
                + TDMathUtils.formattedGeoPtDistanceMiles(userLoc, dish.getLocation())
                + "</distance>");
        boolean isEditable = false;

        if (TDUserService.getUserLoggedIn() && UserServiceFactory.getUserService().isUserAdmin()) {
          isEditable = true;
        } else
          isEditable = TDQueryUtils.isAccessible(Long.valueOf(dish.getKey().getId()), new Dish());
        if (isEditable) sb.append("<allowEdit>T</allowEdit>");
        else sb.append("<allowEdit>F</allowEdit>");
        if (TDUserService.getUserLoggedIn()) {
          sb.append("<userLoggedIn>L</userLoggedIn>");
        } else {
          sb.append("<userLoggedIn>O</userLoggedIn>");
        }
        if (null != dishPhoto) {
          try {
            sb.append(
                "<blobKey>"
                    + ImagesServiceFactory.getImagesService()
                        .getServingUrl(dishPhoto.getBlobKey(), 98, true)
                    + "</blobKey>");
            sb.append("<photoExist>E</photoExist>");
          } catch (Exception e) {
            sb.append("<photoExist>NE</photoExist>");
          }
        } else {
          sb.append("<blobKey></blobKey>");
          sb.append("<photoExist>NE</photoExist>");
        }
        sb.append(
            "<restAddrLine1>"
                + StringEscapeUtils.escapeHtml(r.getAddressLine1())
                + "</restAddrLine1>");
        sb.append("<restCity>" + StringEscapeUtils.escapeHtml(r.getCity()) + "</restCity>");
        sb.append("<restState>" + StringEscapeUtils.escapeHtml(r.getState()) + "</restState>");
        sb.append("<restId>" + r.getKey().getId() + "</restId>");
        sb.append("<restName>" + StringEscapeUtils.escapeHtml(r.getName()) + "</restName>");
        sb.append(
            "<restNeighbourhood>"
                + StringEscapeUtils.escapeHtml(r.getNeighborhood())
                + "</restNeighbourhood>");
        // sb.append("<location>" + dish.getLocation() + "</location>");
        sb.append("<latitude>" + dish.getLocation().getLat() + "</latitude>");
        sb.append("<longitude>" + dish.getLocation().getLon() + "</longitude>");
        sb.append("<posReviews>" + dish.getNumPosReviews() + "</posReviews>");
        sb.append("<negReviews>" + dish.getNumNegReviews() + "</negReviews>");
        String voteString = "LTE0";
        if (vote > 0) voteString = "GT0";
        else if (vote < 0) voteString = "LT0";
        sb.append("<voteString>" + voteString + "</voteString>");
        if (tags != null && !tags.isEmpty()) {
          sb.append("<tagsEmpty>NE</tagsEmpty>");
        } else sb.append("<tagsEmpty>E</tagsEmpty>");
        sb.append("<Tags>");
        for (Tag tag : tags) {
          sb.append(
              "<tag><tagName>" + StringEscapeUtils.escapeHtml(tag.getName()) + "</tagName></tag>");
        }
        sb.append("</Tags>");
        Key lastReviewKey = TDQueryUtils.getLatestReviewByDish(dish.getKey());
        if (null != lastReviewKey) {
          final Review lastReview =
              PMF.get().getPersistenceManager().getObjectById(Review.class, lastReviewKey);
          if (lastReview.getDirection() == Review.POSITIVE_DIRECTION) {
            sb.append("<lastReviewType>P</lastReviewType>");
          } else sb.append("<lastReviewType>N</lastReviewType>");
          sb.append(
              "<lastReview>"
                  + HumanTime.approximately(
                      System.currentTimeMillis() - lastReview.getDateCreated().getTime())
                  + "</lastReview>");
        } else {
          sb.append("<lastReviewType>E</lastReviewType>");
        }
        sb.append("<numReview>" + dish.getNumReviews() + "</numReview>");

        sb.append("</Dish>");
      }
      sb.append("</Dishes>");

      sb.append("</DishSearch>");
    } else {
      namesAdded = true;
      sb.append("<dishMesg>No records found</dishMesg>");
    }

    if (namesAdded) {
      resp.setContentType("text/xml");
      resp.getWriter().write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + sb.toString());
    } else {
      resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
    }
  }
public class AudioClipService {
  DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
  BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
  MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
  UserService userService = new UserService();

  public List<AudioClipInstance> getOtherUsersAudioClips(String userId) throws BadRequestException {
    List<AudioClipInstance> audioClipInstanceList;

    // no need to check for user existance here! if UserId is null, then all audioClips are returned
    Filter userFilter =
        new FilterPredicate(TuneInConstants.AUDIO_CLIP_OWNER_ID, FilterOperator.NOT_EQUAL, userId);
    Query q = new Query(TuneInConstants.AUDIO_CLIP_TYPE).setFilter(userFilter);
    PreparedQuery pq = datastore.prepare(q);

    // check mem-cache for the results first
    String CACHE_KEY = TuneInConstants.OTHERS_WORK_KEY + userId;
    audioClipInstanceList = (ArrayList<AudioClipInstance>) syncCache.get(CACHE_KEY);

    if (audioClipInstanceList == null) {
      audioClipInstanceList = new ArrayList<AudioClipInstance>();
      User user;
      AudioClipInstance audioClipInstance;

      for (Entity result : pq.asIterable()) {
        user =
            userService.getUserById(
                (String) result.getProperty(TuneInConstants.AUDIO_CLIP_OWNER_ID));
        audioClipInstance =
            new AudioClipInstance(
                KeyFactory.keyToString(result.getKey()),
                (String) result.getProperty(TuneInConstants.AUDIO_CLIP_TITLE),
                user,
                (String) result.getProperty(TuneInConstants.AUDIO_CLIP_AUDIO_ID),
                (String) result.getProperty(TuneInConstants.AUDIO_CLIP_IMAGE_ID),
                (Date) result.getProperty(TuneInConstants.AUDIO_CLIP_DATE));
        audioClipInstanceList.add(audioClipInstance);
      }
      syncCache.put(CACHE_KEY, audioClipInstanceList, Expiration.byDeltaSeconds(300));
    }

    return audioClipInstanceList;
  }

  public AudioClip getAudioClipById(String id) throws BadRequestException {
    AudioClip audioClip;
    try {
      Key audio_key = KeyFactory.stringToKey(id);
      Entity result = datastore.get(audio_key);
      audioClip =
          new AudioClip(
              id,
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_TITLE),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_OWNER_ID),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_AUDIO_ID),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_IMAGE_ID),
              (Date) result.getProperty(TuneInConstants.AUDIO_CLIP_DATE));
      return audioClip;
    } catch (Exception e) {
      throw new BadRequestException();
    }
  }

  public List<AudioClip> getAudioClipsByUser(String userId) throws BadRequestException {
    List<AudioClip> audioClipList = new ArrayList<AudioClip>();

    // verify userId
    validateUserExistance(userId); // throws bad request exception of user doesn't exist
    Filter userFilter =
        new FilterPredicate(TuneInConstants.AUDIO_CLIP_OWNER_ID, FilterOperator.EQUAL, userId);
    Query q =
        new Query(TuneInConstants.AUDIO_CLIP_TYPE)
            .setFilter(userFilter)
            .addSort(TuneInConstants.AUDIO_CLIP_DATE, SortDirection.ASCENDING);
    PreparedQuery pq = datastore.prepare(q);
    AudioClip audioClip;
    for (Entity result : pq.asIterable()) {
      audioClip =
          new AudioClip(
              KeyFactory.keyToString(result.getKey()),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_TITLE),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_OWNER_ID),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_AUDIO_ID),
              (String) result.getProperty(TuneInConstants.AUDIO_CLIP_IMAGE_ID),
              (Date) result.getProperty(TuneInConstants.AUDIO_CLIP_DATE));
      audioClipList.add(audioClip);
    }
    return audioClipList;
  }

  public String newAudioClip(String userId, String title, String audio, String image)
      throws BadRequestException {
    // validate existence of the user
    validateUserExistance(userId); // throws bad request exception of user doesn't exist

    Entity audioClip = new Entity(TuneInConstants.AUDIO_CLIP_TYPE);
    audioClip.setProperty(TuneInConstants.AUDIO_CLIP_TITLE, title);
    audioClip.setProperty(TuneInConstants.AUDIO_CLIP_AUDIO_ID, audio);
    audioClip.setProperty(TuneInConstants.AUDIO_CLIP_IMAGE_ID, image);
    audioClip.setProperty(TuneInConstants.AUDIO_CLIP_OWNER_ID, userId);
    audioClip.setProperty(TuneInConstants.AUDIO_CLIP_DATE, new Date());
    datastore.put(audioClip);
    return KeyFactory.keyToString(audioClip.getKey());
  }

  public void deleteAudioClip(String audioClipId) throws BadRequestException {
    AudioClip audioClip = getAudioClipById(audioClipId);
    datastore.delete(KeyFactory.stringToKey(audioClipId));

    // task queue to delete the associated audio and image blobs
    Queue queue = QueueFactory.getDefaultQueue();
    queue.add(
        TaskOptions.Builder.withUrl("/rest/users/" + audioClip.getOwnerId() + "/audioClips/audio")
            .method(TaskOptions.Method.DELETE)
            .param("blobkey", audioClip.getAudioId()));
    queue.add(
        TaskOptions.Builder.withUrl("/rest/users/" + audioClip.getOwnerId() + "/audioClips/image")
            .method(TaskOptions.Method.DELETE)
            .param("blobkey", audioClip.getImageId()));
  }

  public void deleteBlob(String blobkey) {
    BlobKey blob_key = new BlobKey(blobkey);
    blobstoreService.delete(blob_key);
  }

  // memcache only endpoints
  public List<AudioClip> getAudioClipInMemcache() throws BadRequestException {
    ArrayList<AudioClip> audioClipList =
        (ArrayList<AudioClip>) syncCache.get(TuneInConstants.ALL_AUDIO_CLIPS);
    return audioClipList;
  }

  public String newAudioClipInMemcache(String ownerId, AudioClip audioClip)
      throws BadRequestException {
    validateUserExistance(ownerId);
    ArrayList<AudioClip> audioCLipList =
        (ArrayList<AudioClip>) syncCache.get(TuneInConstants.ALL_AUDIO_CLIPS);
    if (audioCLipList == null) {
      audioCLipList = new ArrayList<AudioClip>();
    }
    audioCLipList.add(audioClip);
    syncCache.put(TuneInConstants.ALL_AUDIO_CLIPS, audioCLipList, Expiration.byDeltaSeconds(60));
    return audioClip.getKeyname();
  }

  private void validateUserExistance(String userId) throws BadRequestException {
    // validate existence of the user
    userService.getUserById(userId); // throws bad request exception of user doesn't exist
  }
}
 private static void throwBadRequest(BlobKey blobKey, String s) throws IOException {
   BlobstoreServiceFactory.getBlobstoreService().delete(blobKey);
   throw new IllegalArgumentException(s);
 }
 public static void serveImage(ImageRef ref, HttpServletResponse response) throws IOException {
   BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
   blobstoreService.serve(getBlobkKey(ref), response);
 }
 public static String getUploadUrl(ImageRef ref) {
   BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
   return blobstoreService.createUploadUrl(
       "/backend/image-post-upload?ref=" + BaseEncoding.base64().encode(ref.toByteArray()),
       UploadOptions.Builder.withGoogleStorageBucketName(getBucket()));
 }