4

I'm developing a web application using Google app engine for Java. I will use Google Cloud storage and according to the documentation, I'm using GCS client library to emulate cloud storage on local disk.

I have no problem saving the files, I can see them from eclipse under the war folder (under the path WEB-INF/appengine-generated) and I can see them from the web admin panel accessible from the url

localhost:8888/_ah/admin

as indicated in this question

My question is the following. Which are the files URI under localhost to access them with GCS emulation?

Example of one of uploaded files on localhost:

  • file key is aglub19hcHBfaWRyJwsSF19haF9GYWtlQ2xvdWRTdG9yYWdlX18xIgpxcmNvZGUuanBnDA
  • ID/name is encoded_gs_key:L2dzLzEvcXJjb2RlLmpwZw
  • filename is /gs/1/qrcode.jpg

Thanks in advance.

Community
  • 1
  • 1
  • Can you clarify what you're asking? I don't really understand what you're looking for. – jterrace Jun 17 '13 at 15:55
  • Maybe I don't understand how GCS works. When I upload a file, I expect that it is reachable by an url provided by GCS. Is that right? I have worked with rackspace cloud and it works in that way. Can I access to my GCS file only through my application? Isn't there a public url reachable by anyone? – Michelantonio Trizio Jun 18 '13 at 08:20
  • @MichelantonioTrizio Sei riuscito alla fine a sistemare il problema col GCS? Have you fixed your project because i'm doing quite the same things. Thanks :-) – Aerox Apr 19 '14 at 13:31
  • You must develop a service to call as you can see in the link below. There isn't direct access to the resources. – Michelantonio Trizio Apr 19 '14 at 19:02

3 Answers3

3

You can see how this is done here: https://code.google.com/p/appengine-gcs-client/source/browse/trunk/java/src/main/java/com/google/appengine/tools/cloudstorage/dev/LocalRawGcsService.java

As of today this mapping is being maintained by the using the local datastore. This may change in the future, but you should be able to simply call into this class or one of the higher level classes provided with the GCS client to get at the data.

tkaitchuck
  • 199
  • 3
3

Using getServingUrl()

The local gcs file is saved into a blob format. When saving it, I can use location like your filename "/gs/1/qrcode.jpg" Yet, when accessing it, this fake location is not working. I found a way. It may not be the best, but works for me.

BlobKey bk = BlobstoreServiceFactory.getBlobstoreService().createGsBlobKey(location);
String url = ImagesServiceFactory.getImagesService().getServingUrl(bk);

The url will be like:

http://127.0.0.1:8080/_ah/img/encoded_gs_key:yourkey

(I was hardly to find any direct solution by google search. I hope this answer can help others in need.)

Resource: ImagesServiceFactory ImageService FileServiceFactory

RobinBattle
  • 220
  • 4
  • 14
  • Exactly, its stored in the Entity "__GsFileInfo__" use the entire content in the column called "ID/Name". – drindt Nov 04 '14 at 21:00
0

For those who wish to serve the local GCS files that have been created by the GAE GCS library, one solution is to expose a Java Servlet like this:

package my.applicaion.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

public final class GoogleCloudStorageServlet
  extends HttpServlet
{

  @Override
  protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
      throws ServletException, IOException
  {
    final BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    final String fileName = "/gs" + request.getPathInfo();
    final BlobKey blobKey = blobstoreService.createGsBlobKey(fileName);
    blobstoreService.serve(blobKey, response);
  }

}

and in your web.xml:

<servlet>
  <servlet-name>GoogleCloudStorage</servlet-name>
  <servlet-class>my.applicaion.servlet.GoogleCloudStorageServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>GoogleCloudStorage</servlet-name>
  <url-pattern>/gcs/*</url-pattern>
</servlet-mapping>

If you host this servlet in your GAE application, the URL for accessing a GCS file with bucket bucket-name and with name fileName is http://localhost:8181:/gcs/bucket-name/fileName, the local GAE development server port number being 8181.

This works at least from GAE v1.9.50.

And if you intend to have the local GCS server working in a unit test with Jetty, here is a work-around, hopefully with the right comments:

  final int localGcsPortNumber = 8081;
  final Server localGcsServer = new Server(localGcsPortNumber);
  final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
  final String allPathSpec = "/*";
  context.addServlet(new ServletHolder(new HttpServlet()
  {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
      final BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
      final String fileName = "/gs" + request.getRequestURI();
      final BlobKey blobKey = blobstoreService.createGsBlobKey(fileName);

      if (blobKey != null)
      {
        // This is a work-around over the "ServeBlobFilter" which does not take the "Content-Type" from the "blobInfo", but attempts to retrieve it from the "blobKey"
        final BlobInfo blobInfo = BlobStorageFactory.getBlobInfoStorage().loadGsFileInfo(blobKey);
        if (blobInfo != null)
        {
          final String contentType = blobInfo.getContentType();
          if (contentType != null)
          {
            response.addHeader(HttpHeaders.CONTENT_TYPE, contentType);
          }
        }
      }

      blobstoreService.serve(blobKey, response);
    }

  }), allPathSpec);
  // The filter is responsible for taken the "blobKey" from the HTTP header and for fulfilling the response with the corresponding GCS content
  context.addFilter(ServeBlobFilter.class, allPathSpec, EnumSet.of(DispatcherType.REQUEST));
  // This attribute must be set, otherwise a "NullPointerException" is thrown
  context.getServletContext().setAttribute("com.google.appengine.devappserver.ApiProxyLocal", LocalServiceTestHelper.getApiProxyLocal());
  localGcsServer.setHandler(context);
  localGcsServer.start();
Édouard Mercier
  • 485
  • 5
  • 12