Salesforceのメモ&添付のファイルを一括ダウンロードしたーい。

という話。

Salesforceの
設定⇒データの管理⇒データのエクスポート
とすれば、標準でできるのですが、
1.ダウンロードできるようになるまで時間がかかる。
2.ウィークリー(またはマンスリー)で1回のみ。
3.地味にzipをクリックする作業
なので、使い勝手はあまりよろしくないし、特に2.の設定を間違えたらバックアップは1週間先でリリース中断。
なんてことも考えられます。

AppExchangeでダウンロードするようなものないかな?
って探してみたのですが探し方が足りないのか見当たらなかったので、javaとwindowsコマンドでダウンロードする方式を作ってみることにしました。


まずは、javaでSalesforceにアクセスできるようにするため、jarを作成する作業から。
1.
Salesforceの
設定⇒開発⇒API⇒パートナー WSDL の生成
を右クリックし、partner.wsdlを保存。

2.
wsc.jarをダウンロードします。
gitとか
こことか
こことか
などでダウンロードして、partner.wsdlと同一フォルダにいれておきます。

3.
wsdlからjarを作成します。
コマンドプロンプトを立ち上げて、cd コマンドで、先ほどダウンロードしたフォルダ階層に移動。
そして、
java -classpath wsc-XX.jar com.sforce.ws.tools.wsdlc partner.wsdl partner.jar
とすると、partner.jarが作成されます。


ここまで、準備したら次にjavaコーディング。(私の開発環境の都合上java6で書いた)
きれいなコーディングとはいえませんが、下記のようなコーディングをしました。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import com.sforce.soap.partner.Connector;
import com.sforce.soap.partner.LoginResult;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.soap.partner.QueryResult;
import com.sforce.soap.partner.sobject.SObject;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;

/**
 * メモ&添付のファイルをBASE64として出力する。
 */
public class SFDCFileDownload {

    public static void main(String[] args) {

        SFDCFileDownload sfdcFileDownload = new SFDCFileDownload();
        try {
            sfdcFileDownload.execute();
        } catch (Exception e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
    }

    /**
     * @throws Exception
     */
    private void execute() throws Exception {
        Properties prop = null;
        PartnerConnection connection = null;

        try {
            // プロパティファイルの読み込んでプロパティ情報を取得
            prop = readProperties();

            // Salesforce環境へのログインしコネクション情報を取得
            connection = loginSFDC(prop);

            // メモ&添付ファイルの読み込みとファイル出力
            readAttachment(prop, connection);

        } catch (Exception e) {
            throw e;
        } finally {
            // Salesforceのログアウト
            if (connection != null) {
                connection.logout();
            }
        }

    }

    /**
     * プロパティファイルの読み込み
     * @throws IOException
     */
    private Properties readProperties() throws IOException {

        Properties prop = new Properties();

        // プロパティファイルの読み込み
        BufferedReader br = new BufferedReader(new FileReader(
                "fileDownload.properties"));

        prop.load(br);

        return prop;

    }

    /**
     * SFDCへのログインまで
     * @param prop
     * @return SFのコネクション情報
     * @throws ConnectionException
     */
    private PartnerConnection loginSFDC(Properties prop)
            throws ConnectionException {

        // ログインの設定。
        ConnectorConfig config = new ConnectorConfig();
        config.setUsername(prop.getProperty("userName"));
        config.setPassword(prop.getProperty("userPassword"));

        // 本番orSandbox。ここも後にパラメータ化
        config.setAuthEndpoint(prop.getProperty("url"));

        // 接続
        PartnerConnection connection = Connector.newConnection(config);

        LoginResult lr = connection.login(prop.getProperty("userName"),
                prop.getProperty("userPassword"));

        System.out.println("--------------------------------");
        System.out.println(lr.getUserInfo().getOrganizationName());
        System.out.println(lr.getUserInfo().getUserFullName());
        System.out.println("login success...");
        System.out.println("--------------------------------");

        return connection;
    }

    /**
     * メモ&添付を検索、ファイルを出力する。
     * @param prop プロパティ
     * @param connection コネクション
     * @throws ConnectionException
     * @throws IOException
     */
    private void readAttachment(Properties prop, PartnerConnection connection)
            throws ConnectionException, IOException {

        // 出力先フォルダを作成する。
        Date date = new Date();
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        File beforeDir = new File("before" + df.format(date));
        if (!beforeDir.exists()) {
            beforeDir.mkdir();
        }

        File afterDir = new File("after" + df.format(date));
        if (!afterDir.exists()) {
            afterDir.mkdir();
        }

        // バッチ用のファイル出力
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(
                new FileOutputStream("base64Decode.bat"), "MS932"));

        // メモ&添付の全件検索。
        StringBuilder soqlQuery = new StringBuilder();
        soqlQuery.append("SELECT ");
        soqlQuery.append("ID, ");
        soqlQuery.append("Name, ");
        soqlQuery.append("Body ");
        soqlQuery.append("FROM ");
        soqlQuery.append("Attachment ");

        QueryResult rs = connection.query(soqlQuery.toString());

        // 1件ずつ抽出添付を抽出。
        boolean done = false;
        while (!done) {
            for (int i = 0; i < rs.getRecords().length; i++) {
                SObject record = rs.getRecords()[i];

                // ファイル名を設定
                String fileName = null;
                if ("1".equals(prop.getProperty("fileName"))) {
                    // Idのみ
                    fileName = record.getId();
                } else {
                    // IDと拡張子
                    // 拡張子のチェック
                    int point = record.getField("Name").toString()
                            .lastIndexOf(".");
                    if (point == -1) {
                        fileName = record.getId();
                    } else {
                        fileName = record.getId()
                                + record.getField("Name").toString()
                                        .substring(point);
                    }
                }

                // ファイル出力
                FileOutputStream writer = new FileOutputStream(beforeDir
                        + File.separator + fileName);
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                        writer));

                String str = record.getField("Body").toString();
                bw.write(str);

                bw.flush();
                bw.close();
                writer.close();

                // バッチ用のファイル書き込み
                StringBuilder sb = new StringBuilder("certutil -decode ");
                sb.append("\"");
                sb.append(beforeDir);
                sb.append(File.separator);
                sb.append(fileName);
                sb.append("\" \"");
                sb.append(afterDir);
                sb.append(File.separator);
                sb.append(fileName);
                sb.append("\"");
                pw.println(sb.toString());

            }

            if (rs.isDone()) {
                done = true;
            } else {
                rs = connection.queryMore(rs.getQueryLocator());
            }
        }

        pw.close();

    }
}


コーディング内のプロパティファイルは以下のような内容です。
#Salesforceにログインするユーザ名とパスワード
#SalesforceのIP設定によっては、パスワードの後ろにセキュリティトークンもつける必要有。
userName=xxxxxxxxxxxxxxxx@salesforce.com
userPassword=xxxxxx

#SalesforceへのURL:
url=https://login.salesforce.com/services/Soap/u/34.0
#url=https://test.salesforce.com/services/Soap/u/34.0


#ファイル名の出力方法
#1:Id
#2:Id##ファイル名(拡張子あり、windowsで使えない文字は@変換)(うまくいかないので今のところ非推奨)
#3:Id+拡張子
fileName=3


Bodyの内容を見るとBASE64形式の文字列でした。
私のやり方が悪いのか、
ObjectOutputStream.write(Base64.decode(・・・))
のようにしてファイル出力させようとしたのですが、ファイルが壊れてうまくいかず。

そのため、BufferedWriterでテキストとして出力させたあと、全ファイルをコマンドラインの「certUtil -decode」で変換する方式としました。
コマンドラインの内容も一緒に吐き出しているので、javaを起動した後、作成したバッチを動かせばファイルがローカルにばっちり作られました。

めんどくさいので、java(特に意味はなかったけどjarにした)とデコードバッチを起動するバッチも作成。

@echo off
setlocal

rem *********************************************************
rem メモ&添付のファイルをダウンロードします。
rem *********************************************************

java -classpath AttachmentDownload.jar;lib\* SFDCFileDownload

rem *********************************************************
rem ダウンロードしたBASE64のファイルをデコードします
rem *********************************************************

call base64Decode.bat


バックアップしたものをアップロードする方法ですが、そこは未検討。
データローダでできるみたいですが、どうしましょうね。


参考文献
javaのAPI:http://docs.oracle.com/javase/jp/6/api/
java開発者環境の設定:https://developer.salesforce.com/docs/atlas.ja-jp.salesforce_developer_environment_tipsheet.meta/salesforce_developer_environment_tipsheet/salesforce_developer_environment_java_stubs.htm
terraSkyさんのブログ記事:http://www.terrasky.co.jp/blog/2014/140430_001345.php
Pa-kun plus ideaさんのブログ記事:http://web.plus-idea.net/2012/03/salesforce-download/

関連記事


--------------------------------------------------------------------------------------

コメントの投稿

非公開コメント

このブログについて
  • 全記事一覧(時間順)
  • このブログについて
  • 私のプロフィール
  • 当ブログで扱っている動画について
  • 記事違いなコメントのお返事

  • カテゴリー
    twitter
    カレンダー
    09 | 2017/10 | 11
    1 2 3 4 5 6 7
    8 9 10 11 12 13 14
    15 16 17 18 19 20 21
    22 23 24 25 26 27 28
    29 30 31 - - - -
    Amazon
    でたらめな当ブログにぴったりな商品を自動で表示するみたいです。



    月別アーカイブ
    プロフィール

    たづみ

    Author:たづみ
    ・1981年生まれの男
    ・もう少し詳細なプロフィールはこちらで

    最新コメント
    アクセスランキング
    [ジャンルランキング]
    日記
    831位
    アクセスランキングを見る>>

    [サブジャンルランキング]
    会社員・OL
    176位
    アクセスランキングを見る>>