2010年11月21日日曜日

Evernote API を使ってみる (5) リソースつきノート作成

画像やPDFといったノートの添付ファイルは「リソース」として扱う。リソースはノートに紐づくもので、単体で作成したり削除したりすることはできない(取得とメタデータの更新はできる)。リソースの扱いは(バイナリデータという性質上)他のタイプに比べるとかなり面倒。

リソースつきのノートを作成するには、以下の手順になる。

  1. 新規ノートを作成
  2. 新規リソースを作成
    -バイナリデータを設定
    -MIMEタイプを設定
    -必要ならファイル名など属性(メタデータ)を設定
  3. ノートにリソースを追加
  4. ノートのコンテンツにリソースを参照するためのen-mediaタグを追加
    -参照にはデータのハッシュ(MD5チェックサム)を使う。
  5. サービスのcreateNote()メソッドをコール
既存のノートにリソースを追加したり、削除したりするには、ノートが持っているリソースリストを変更したうえでupdateNote()をコールする。

リソースを取得するには、ノートからたどることも、リソース単体で取得することもできる。単体で取得するには、直接GUIDを指定する(そもそもリソースのGUIDなんかとってくるのが面倒><)か、ノートのGUID&リソースデータのハッシュ値を指定して取得する。ノートやリソースを取得する getNote() や getResource() には、バイナリデータやリソースの属性などを取得するかどうかのフラグがあって、必要なときだけ true を指定させるようになっている。必要ないものは全部 false にしておく。

リソースとリソースつきノートを操作するテストプログラムがこちら。
public class ResourceTest {

    private static String consumerKey = "consumer key";
    private static String consumerSecret = "consumer secret";
    private static String evernoteHost = "sandbox.evernote.com";
    private static String userName = "user name";
    private static String password = "password";

    private static NoteStore.Client setupNoteStore(String evernoteHost, User user) throws TException {
        // NoteStore クライアントのセットアップ
        String noteStoreUrl = "https://" + evernoteHost + "/edam/note/" + user.getShardId();
        THttpClient trans = new THttpClient(noteStoreUrl);
        TBinaryProtocol prot = new TBinaryProtocol(trans);
        NoteStore.Client noteStore = new NoteStore.Client(prot, prot);
        return noteStore;
    }

    // ファイルからバイナリストリームを読み込んでデータオブジェクトを作成するメソッド
    // 付属のサンプルコードからコピペしたもの
    private static Data readFileAsData(String fileName) throws Exception {
        FileInputStream in = new FileInputStream(fileName);
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        byte[] block = new byte[10240];
        int len;
        while ((len = in.read(block)) >= 0) {
            byteOut.write(block, 0, len);
        }
        in.close();
        byte[] body = byteOut.toByteArray();
        Data data = new Data();
        data.setSize(body.length);
        data.setBodyHash(MessageDigest.getInstance("MD5").digest(body));
        data.setBody(body);
        return data;
    }

    // ハッシュ値(バイナリ配列)を文字列に変換するメソッド
    // 付属のサンプルコードからコピペしたもの
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte hashByte : bytes) {
            int intVal = 0xff & hashByte;
            if (intVal < 0x10) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(intVal));
        }
        return sb.toString();
    }
    
    public static void main(String[] args) {
        UserStore.Client userStore = null;
        NoteStore.Client noteStore = null;
        AuthenticationResult authResult = null;
        try {
            userStore = AuthUtil.setupUserStore(evernoteHost);
            authResult = AuthUtil.authenticate(userStore, consumerKey, consumerSecret, evernoteHost, userName, password);
            User user = authResult.getUser();
            String authToken = authResult.getAuthenticationToken();
            
            noteStore = setupNoteStore(evernoteHost, user);
            
            Notebook notebook = noteStore.getDefaultNotebook(authToken);
            
            // リソースつき新規ノート作成
            System.out.println("** CREATE NOTE WITH RESOURCES **");
            Note note = new Note();
            note.setNotebookGuid(notebook.getGuid());
            note.setTitle("Testnote with Resources - " + new Date().getTime());
            
            // リソース作成
            Resource resource1 = new Resource();
            resource1.setData(readFileAsData("image/neko.jpg")); // バイナリデータ
            resource1.setMime("image/jpeg"); // MIMEタイプ
            ResourceAttributes atts1 = new ResourceAttributes(); // リソースの属性
            atts1.setFileName("neko.jpg");
            resource1.setAttributes(atts1);
            note.addToResources(resource1); // ノートにリソースを追加
            String hashHex1 = bytesToHex(resource1.getData().getBodyHash()); // リソースのハッシュ値(MD5チェックサム)
            
            Resource resource2 = new Resource();
            resource2.setData(readFileAsData("image/tori.jpg"));
            resource2.setMime("image/jpeg");
            ResourceAttributes atts2 = new ResourceAttributes();
            atts2.setFileName("tori.jpg");
            resource2.setAttributes(atts2);
            note.addToResources(resource2);
            String hashHex2 = bytesToHex(resource2.getData().getBodyHash());
            // ノートのコンテンツ。en-mediaタグにリソースのハッシュ値、MIMEタイプを入れる。
            String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
                + "<en-note>Pictures:<br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex1 + "\"/><br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex2 + "\"/>"
                + "</en-note>";
            note.setContent(content);
            
            Note created = noteStore.createNote(authToken, note);
            System.out.println("ノート\"" + created.getTitle() + "\"を作成しました。");
            System.out.println("ノート\"" + created.getTitle() + "\"のリソース数: " + created.getResourcesSize());
            for (Resource resource : created.getResources()) {
                System.out.print(" - " + resource.getAttributes().getFileName());
                System.out.println(" (guid=" + resource.getGuid() + ")");
            }
            
            // リソースを追加してノートを更新
            System.out.println("** ADD RESOURCE **");
            Resource resource3 = new Resource();
            resource3.setData(readFileAsData("image/inu.jpg"));
            resource3.setMime("image/jpeg");
            ResourceAttributes atts3 = new ResourceAttributes();
            atts3.setFileName("inu.jpg");
            resource3.setAttributes(atts3);
            created.addToResources(resource3);
            String hashHex3 = bytesToHex(resource3.getData().getBodyHash());
            String content_update1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
                + "<en-note>Pictures:<br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex1 + "\"/><br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex2 + "\"/><br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex3 + "\"/>"
                + "</en-note>";
            created.setContent(content_update1);
            Note updated1 = noteStore.updateNote(authToken, created);
            System.out.println("ノート\"" + updated1.getTitle() + "\"を更新しました。");
            System.out.println("ノート\"" + updated1.getTitle() + "\"のリソース数: " + updated1.getResourcesSize());
            for (Resource resource : updated1.getResources()) {
                System.out.print(" - " + resource.getAttributes().getFileName());
                System.out.println(" (guid=" + resource.getGuid() + ")");
            }

            // リソースを削除してノートを更新
            System.out.println("** REMOVE RESOURCE **");
            Iterator<Resource> it = updated1.getResourcesIterator();
            while(it.hasNext()) {
                Resource r = it.next();
                if (bytesToHex(r.getData().getBodyHash()).equals(hashHex1)) {
                    it.remove();
                }
            }
            String content_update2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
                + "<en-note>Pictures:<br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex2 + "\"/><br/>"
                + "<en-media type=\"image/jpeg\" hash=\"" + hashHex3 + "\"/>"
                + "</en-note>";
            updated1.setContent(content_update2);
            Note updated2 = noteStore.updateNote(authToken, updated1);
            System.out.println("ノート\"" + updated2.getTitle() + "\"を更新しました。");
            System.out.println("ノート\"" + updated2.getTitle() + "\"のリソース数: " + updated2.getResourcesSize());
            for (Resource resource : updated2.getResources()) {
                System.out.print(" - " + resource.getAttributes().getFileName());
                System.out.println(" (guid=" + resource.getGuid() + ")");
            }
            
            // リソースをGUIDで指定して取得
            System.out.println("** GET RESOURCE BY ID **");
            String guid = updated2.getResources().get(0).getGuid();
            Resource r = noteStore.getResource(authToken, guid, false, false, true, false);
            System.out.println("リソース\"" + r.getAttributes().getFileName() + "\"を取得しました。(guid=" + r.getGuid() + ")");

            // リソースをノートGUIDとハッシュ値で指定して取得
            System.out.println("** GET RESOURCE BY NOTE ID AND HASH **");
            byte[] hash = updated2.getResources().get(0).getData().getBodyHash();
            Resource r2 = noteStore.getResourceByHash(authToken, updated2.getGuid(), hash, false, false, false);
            System.out.println("リソース\"" + r2.getAttributes().getFileName() + "\"を取得しました。(guid=" + r2.getGuid() + ")");

            // リソースを更新(メタデータのみ可)
            System.out.println("** UPDATE RESORCE **");
            String fileName = r2.getAttributes().getFileName();
            r2.getAttributes().setFileName("update_" + fileName);
            noteStore.updateResource(authToken, r2);
            Resource r2_updated = noteStore.getResource(authToken, r2.getGuid(), false, false, true, false);
            System.out.println("リソース\"" + r2_updated.getAttributes().getFileName() + "\"が更新されました。(guid=" + r2_updated.getGuid() + ")");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

実行例。
** CREATE NOTE WITH RESOURCES **
ノート"Testnote with Resources - 1290298760809"を作成しました。
ノート"Testnote with Resources - 1290298760809"のリソース数: 2
 - tori.jpg (guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)
 - neko.jpg (guid=c800bf58-0ee4-47b0-bc4b-a8556ea2b830)
** ADD RESOURCE **
ノート"Testnote with Resources - 1290298760809"を更新しました。
ノート"Testnote with Resources - 1290298760809"のリソース数: 3
 - tori.jpg (guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)
 - neko.jpg (guid=c800bf58-0ee4-47b0-bc4b-a8556ea2b830)
 - inu.jpg (guid=96815797-6ee6-4694-a784-6c81c9eaeb10)
** REMOVE RESOURCE **
ノート"Testnote with Resources - 1290298760809"を更新しました。
ノート"Testnote with Resources - 1290298760809"のリソース数: 2
 - tori.jpg (guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)
 - inu.jpg (guid=96815797-6ee6-4694-a784-6c81c9eaeb10)
** GET RESOURCE BY ID **
リソース"tori.jpg"を取得しました。(guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)
** GET RESOURCE BY NOTE ID AND HASH **
リソース"tori.jpg"を取得しました。(guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)
** UPDATE RESORCE **
リソース"update_tori.jpg"が更新されました。(guid=f2f0d0d6-3a5e-4007-867d-2bafccf4bcec)

0 件のコメント:

コメントを投稿