[Google Drive API v3] Googleドメインが変更になるので自分がオーナーのファイルをすべて移動させてみた

使用しているGoogleのドメインを変更することになったので、
自分がオーナーのファイルのオーナー権限を移設先のドメインに
譲渡しようと試みました。

しかし。。。共有はできるけどオーナー権限を移すことができない！
なんでも、
<font color=red>「オーナー権限は同じドメイン内のユーザーのみに譲渡できる」</font>
らしいです。
仕方がないので、よく使うファイルは手動で移して、残りの古いファイルは
Google Drive APIを使って移すことにしました。
隙間時間の30分ほどでさくっと作りましたので細かい部分は目をつむってください。

## 1. やっていること
1- 移設元のオーナーファイルを検索

2- 対象ファイルに移設先アカウントの編集権限をつける

3- 対象ファイルを移設先の指定フォルダにコピー（指定がなければマイドライブ）

## 2. プログラム

### 2.1. main
1- 以下を引数で受け取ります
|引数|内容|
|---|---|
|第1引数|移設元のメールアドレス(Googleアカウント)|
|第2引数|移設元のOAuthクライアントキーのパス|
|第3引数|移設先のメールアドレス(Googleアカウント)|
|第4引数|移設先のOAuthクライアントキーのパス|
|第5引数|[オプション]移設先のフォルダID|

2- 「./next/token」のファイルが存在するか確認します
　ファイルが存在したら、保存したトークンを開始としてファイルリストを取得します

　取得したらすぐに消します

3- [2.2. ファイルコピーの実行](#22-ファイルコピーの実行)を繰り返し実行します
　次のトークンがNULLを返すまで繰り返します
 
4- エラーの場合、失敗したトークンを「./next/token」のファイルに保存します
　再度、同じコマンドを実行したらエラーの続きから実行されるようにしています
　プログラム内でリトライしなかった理由は、APIの回数制限によるエラーを考え、
　手動で再開できるように作りました。

```java
public static void main(String[] args) throws Exception{
    if(args.length<4) {
        System.out.println("引数の指定が足りません(第４引数までは必須です)");
        System.out.println("第1引数：移設元のメールアドレス(Googleアカウント)");
        System.out.println("第2引数：移設元のOAuthクライアントキーのパス");
        System.out.println("第3引数：移設先のメールアドレス(Googleアカウント)");
        System.out.println("第4引数：移設先のOAuthクライアントキーのパス");
        System.out.println("第5引数：[オプション]移設先のフォルダID");
        return;
    }
    String mail_dest = args[0];	//移設元のメールアドレス(Googleアカウント)
    String json_dest = args[1];	//移設元のOAuthクライアントキーのパス
    String mail_new = args[2];	//移設先のメールアドレス(Googleアカウント)
    String json_new = args[3];	//移設先のOAuthクライアントキーのパス
    String folder_new = args.length>=5 ? args[4] : null;	//移設先のフォルダID
    String start_token = null;	//読み込み開始トークン
    java.io.File read = new java.io.File("./next/token");
    if(read.isFile()) {
        try(FileReader fileReader = new FileReader(read);
            BufferedReader buf = new BufferedReader(fileReader)){
            start_token = buf.readLine();
        }
        read.delete();
    }
    Drive drive_dest = getDrive(json_dest,true);
    Drive drive_new = getDrive(json_new,false);
    
    String token = start_token;
    for(int i=0; i==0 || token!=null;i++) {
        System.out.println("count["+(i+1)+"]");
        try {
            token = exec(token,drive_dest,mail_dest,drive_new,mail_new,folder_new);
        }catch(Exception e) {
            System.out.println(token);
            java.io.File dir = new java.io.File("./next");
            if(!dir.isDirectory())	dir.mkdir();
            
            java.io.File next = new java.io.File("./next/token");
            if(!next.isFile())	next.createNewFile();
            try(FileWriter writer = new FileWriter(next)){
                writer.write(token);
            }
            throw e;
        }
    }
    System.out.println("終了!!");
}
```

#### 2.2. ファイルコピーの実行
1- 指定したトークンを開始として移設元のファイルリストを取得

2- 自分がオーナーのファイルに対して、移設先のメールアドレスのwrite権限をつける

3- 対象のファイルを移設先の指定フォルダにコピー

```java
/**
 * ファイルのコピー処理を実行
 * @param token			ページトークン
 * @param drive_dest	移設元のDriveオブジェクト
 * @param mail_dest		移設元のメールアドレス(Googleアカウント)
 * @param drive_new		移設先のDriveオブジェクト
 * @param mail_new		移設先のメールアドレス(Googleアカウント)
 * @param folder_new	コピー先のフォルダID
 * @return
 * @throws Exception
 */
public static String exec(String token, Drive drive_dest, String mail_dest, Drive drive_new, String mail_new, String folder_new) throws Exception{
    String ret = null;
    Drive.Files.List list = drive_dest.files().list().setFields("*");
    if(token!=null) {
        list.setPageToken(token);
    }
    FileList res = list.execute();
    ret = res.getNextPageToken();
    System.out.println("ファイル数："+res.getFiles().size()+"件 処理中");
    for(File file : res.getFiles()) {
        if(file.getMimeType().endsWith("folder"))	continue;
        
        boolean permission = true;
        boolean owner = false;
        if(file.getPermissions()==null) continue;
        
        for(Permission p : file.getPermissions()) {
            if(p.getEmailAddress()==null)	continue;
            
            //コピー元がオーナーか？
            if(p.getRole().equals("owner") && p.getEmailAddress().equals(mail_dest)) {
                owner = true;
            }
            //コピー先の権限が設定済みか？
            if(p.getEmailAddress().equals(mail_new)) {
                permission = false;
            }
            if(owner && !permission)	break;
        }
        
        if(owner) {
            System.out.println("["+file.getName()+"] "+ file.getId());
            //権限付与
            if(permission) {
                drive_dest.permissions().create(file.getId(), new Permission().setEmailAddress(mail_new).setType("user").setRole("writer")).execute();
            }
            //ファイルのコピー
            File f = new File().setName(file.getName());
            if(folder_new!=null) {	//コピー先のフォルダの指定があればフォルダIDを指定
                f.setParents(Arrays.asList(folder_new));
            }
            drive_new.files().copy(file.getId(), f).setFields("*").execute();
        }
    }
    return ret;
}
```
### 2.3. Driveオブジェクトの取得
Driveオブジェクトを取得します。

移設元なら「./token_dest」
移設先なら「./token_new」
に認証情報を保存します。

```java
private static Drive getDrive(String quthJson,boolean dest) throws Exception {
    HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
    JsonFactory jsonFactory = GsonFactory.getDefaultInstance();
    
    try(Reader reader = new InputStreamReader(new FileInputStream(quthJson))){
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory,reader);

        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                transport, jsonFactory, clientSecrets, 
                Arrays.asList(DriveScopes.DRIVE))
            .setDataStoreFactory(new FileDataStoreFactory(new java.io.File("./token_"+(dest ? "dest" : "new"))))
            .build();
        
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().build();
        Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
        
        return new Drive.Builder(transport, jsonFactory, credential).build();
    }
}
```
<br>
<br>
おしまい。。