javamavengoogle-app-enginegoogle-drive-api

The API package 'memcache' or call 'Get()' was not found


I am working through the Google Drive API examples that can be found at the following sites: Using Service Accounts, Inserting a File, and Setting Permissions. As you might guess, I'm just getting started with the Google APIs. As such, I'm sure the answer is out there but my knowledge on this topic is not yet broad enough to interpret the findings.

Anyhow, using Google's example code, I have successfully connected to Drive for my service account. I cannot, however, insert a file. I receive the following error:

com.google.apphosting.api.ApiProxy$CallNotFoundException: The API package 'memcache' or call 'Get()' was not found.
    at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:162)
    at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:160)
    at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:86)
    at com.google.appengine.api.memcache.MemcacheServiceImpl.quietGet(MemcacheServiceImpl.java:26)
    at com.google.appengine.api.memcache.MemcacheServiceImpl.get(MemcacheServiceImpl.java:49)
    at com.google.appengine.api.appidentity.AppIdentityServiceImpl.getAccessToken(AppIdentityServiceImpl.java:188)
    at com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential.intercept(AppIdentityCredential.java:93)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
    at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequestWithoutGZip(MediaHttpUploader.java:545)
    at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequest(MediaHttpUploader.java:562)
    at com.google.api.client.googleapis.media.MediaHttpUploader.executeUploadInitiation(MediaHttpUploader.java:519)
    at com.google.api.client.googleapis.media.MediaHttpUploader.resumableUpload(MediaHttpUploader.java:384)
    at com.google.api.client.googleapis.media.MediaHttpUploader.upload(MediaHttpUploader.java:336)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:418)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
    at DriveTest.GDrive.insertFile(GDrive.java:80)
    at DriveTest.GDrive.putFile(GDrive.java:58)
    at DriveTest.App.main(App.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
The API package 'memcache' or call 'Get()' was not found.

Code is pretty much cut-and-paste from the sites I referenced above:

The first line listed is the line that causes the error.

File file = service.files().insert(body, mediaContent).execute();
package DriveTest;
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer;
import com.google.api.client.googleapis.services.GoogleClientRequestInitializer;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;
import com.google.api.services.drive.model.Permission;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;



    public class GDrive {
    
        private static GDrive instance=null;
        private static Drive drive=null;
        private static final String API_KEY = "ourkey";
    
        protected GDrive() {}
    
        public static GDrive getInstance() {
            if(instance==null) {
                instance=new GDrive();
    
            }
            return instance;
        }
    
        public void setDriveService() throws GeneralSecurityException,IOException, URISyntaxException {
            if(drive==null) {
                HttpTransport httpTransport = new NetHttpTransport();
                JsonFactory jsonFactory = new JacksonFactory();
                ArrayList<String> scopes=new ArrayList<String>();
                scopes.add(DriveScopes.DRIVE);
                AppIdentityCredential credential = new AppIdentityCredential.Builder(scopes).build();
                GoogleClientRequestInitializer keyInitializer = new CommonGoogleClientRequestInitializer(API_KEY);
                drive = new Drive.Builder(httpTransport, jsonFactory, null)
                        .setHttpRequestInitializer(credential)
                        .setGoogleClientRequestInitializer(keyInitializer)
                        .build();
            }
        }
    
        public void putFile(String filename) throws Exception {
            File theFile=this.insertFile(this.drive, "Report", "a report!","","application/vnd.ms-excel",filename);
            Permission thePermission=this.setShare(this.drive, theFile.getId(),"someuser@somedomain.com","user","reader");
        }
    
        private File insertFile(Drive service, String title, String description,
                                       String parentId, String mimeType, String filename) {
            // File's metadata.
            File body = new File();
            body.setTitle(title);
            body.setDescription(description);
            body.setMimeType(mimeType);
    
            // Set the parent folder.
            if (parentId != null && parentId.length() > 0) {
                body.setParents(
                        Arrays.asList(new ParentReference().setId(parentId)));
            }
    
            // File's content.
            java.io.File fileContent = new java.io.File(filename);
            FileContent mediaContent = new FileContent(mimeType, fileContent);
            try {
                File file = service.files().insert(body, mediaContent).execute();
    
                // Uncomment the following line to print the File ID.
                System.out.println("File ID: %s" + file.getId());
    
                return file;
            } catch (IOException e) {
                System.out.println("An error occured: " + e);
                return null;
            }
        }
    
        /**
         * Insert a new permission.
         *
         * @param service Drive API service instance.
         * @param fileId ID of the file to insert permission for.
         * @param value User or group e-mail address, domain name or {@code null}
        "default" type.
         * @param type The value "user", "group", "domain" or "default".
         * @param role The value "owner", "writer" or "reader".
         * @return The inserted permission if successful, {@code null} otherwise.
         */
        private Permission setShare(Drive service, String fileId,
                                    String value, String type, String role) throws Exception {
    
            Permission newPermission = new Permission();
    
            newPermission.setValue(value);
            newPermission.setType(type);
            newPermission.setRole(role);
            try {
                return service.permissions().insert(fileId, newPermission).execute();
            } catch (IOException e) {
                System.out.println("An error occurred: " + e);
            }
            return newPermission;
        }
    
    }

Finally, I am using Maven to handle dependencies:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>DriveTest</groupId>
  <artifactId>DriveTest</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>DriveTest</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
      <dependency>
          <groupId>com.google.api-client</groupId>
          <artifactId>google-api-client</artifactId>
          <version>1.17.0-rc</version>
      </dependency>
      <dependency>
          <groupId>com.google.api-client</groupId>
          <artifactId>google-api-client-appengine</artifactId>
          <version>1.17.0-rc</version>
      </dependency>
      <dependency>
          <groupId>com.google.apis</groupId>
          <artifactId>google-api-services-drive</artifactId>
          <version>v2-rev105-1.17.0-rc</version>
      </dependency>
      <dependency>
          <groupId>com.google.http-client</groupId>
          <artifactId>google-http-client-jackson</artifactId>
          <version>1.17.0-rc</version>
      </dependency>
      <dependency>
          <groupId>com.google.appengine</groupId>
          <artifactId>appengine-api-1.0-sdk</artifactId>
          <version>1.8.1</version>
      </dependency>
  </dependencies>
</project>

I am sure I have missed something, but not sure what that is.


Solution

  • Well, I got this to work but the answer was not wholly satisfying. According to The Google SDK Documentation for Service Accounts, there are two ways to go about authenticating with them.

    The first is to create a certificate (detailed in the link above), and use that and the service email account address. The second is to use the email account and the api key. That second method is the one I was using.

    The documentation warns:

    "Note: When authenticating your application using an API Key parameter - instead of using the Client ID and Client Secret method - all application-specific features of the Google Drive API will be disabled as this method is less trusted. For instance the Drive per file scope and the Application Data folder cannot be used."

    However, I could find no useful information that detailed why I was receiving the error that prompted this question.

    So, to solve the problem, I switched to using the email address with the certificate file and it worked just fine.

    Here's the code, straight for the link:

    import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
    import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer;
    import com.google.api.client.googleapis.services.GoogleClientRequestInitializer;
    import com.google.api.client.http.HttpTransport;
    import com.google.api.client.http.javanet.NetHttpTransport;
    import com.google.api.client.json.JsonFactory;
    import com.google.api.client.json.jackson.JacksonFactory;
    import com.google.api.services.drive.Drive;
    import com.google.api.services.drive.DriveScopes;
    ...
    
    /** The API Key of the project */
    private static final String API_KEY = "the_api_key_of_the_project";
    
    /**
     * Build and returns a Drive service object authorized with the
     * application's service accounts.
     *
     * @return Drive service object that is ready to make requests.
     */
    public static Drive getDriveService() throws GeneralSecurityException,
        IOException, URISyntaxException {
      HttpTransport httpTransport = new NetHttpTransport();
      JsonFactory jsonFactory = new JacksonFactory();
      AppIdentityCredential credential =
          new AppIdentityCredential.Builder(DriveScopes.DRIVE).build();
      GoogleClientRequestInitializer keyInitializer =
          new CommonGoogleClientRequestInitializer(API_KEY);
      Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
          .setHttpRequestInitializer(credential)
          .setGoogleClientRequestInitializer(keyInitializer)
          .build();
      return service;
    }
    

    Substituted this in to my setDriveService() and everything worked great.