2013-12-08

Force.com : オブジェクトにカスタム項目を大量に追加したい


この記事は Force.com Advend Calender 2013 8日目の記事です。



オブジェクトにカスタム項目を大量に追加したい

めんどい。
細かいこと(ユニーク制約、必須項目、ヘルプテキスト等)は画面で行うとして、ある程度タグを作成して .object ファイルにぺりっと貼って保存してしまえば OK な感じにしておく。



◇ 用意するもの

  • CommonLisp 系処理
※ xyzzy-lisp で動いたので大概動く気がします



◆ .object

■ テキスト
<fields>
    <fullName>API参照名</fullName>
    <externalId>false</externalId>
    <label>ラベル</label>
    <length>100</length>
    <required>false</required>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Text</type>
    <unique>false</unique>
</fields>

■ テキストエリア
<fields>
    <fullName>API参照名</fullName>
    <externalId>false</externalId>
    <label>ラベル</label>
    <required>false</required>
    <trackFeedHistory>false</trackFeedHistory>
    <type>TextArea</type>
</fields>

■ チェックボックス
<fields>
    <fullName>API参照名</fullName>
    <defaultValue>false</defaultValue>
    <externalId>false</externalId>
    <label>ラベル</label>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Checkbox</type>
</fields>

■ 選択リスト
<fields>
    <fullName>API参照名</fullName>
    <externalId>false</externalId>
    <label>ラベル</label>
    <picklist>
        <picklistValues>
            <fullName>選択肢1</fullName>
            <default>false</default>
        </picklistValues>
        <picklistValues>
            <fullName>選択肢2</fullName>
            <default>false</default>
        </picklistValues>
        <sorted>false</sorted>
    </picklist>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Picklist</type>
</fields>



◆ 実装

■ ファイル(カンマ区切り)
type ラベル API参照名 その他 その他
Text ラベル API参照名(__cを除く) 文字数
TextArea ラベル API参照名(__cを除く)
Checkbox ラベル API参照名(__cを除く)
Picklist ラベル API参照名(__cを除く) 選択肢1 選択肢2
ex.)
Checkbox,有効,Isvalid
Text,名前,Name,255
Picklist,性別,Sex,男性,女性
TextArea,備考,Note

■ プログラム
(defun split(str)
  (let ((retval) (spf 0) (spe 0))
    (loop
      (setq spe (position #\comma str :start spf))
      (cond (spe (setq retval (cons (subseq str spf spe) retval)))
            (t
             (setq retval (cons (subseq str spf) retval))
             (return (reverse retval))))
      (setq spf (1+ spe)))))



(with-open-file (in "C:\\test.txt" :direction :input)
  (let ((line) (sp))
    (while (setq line (read-line in nil))
      (setq sp (split line))
      (cond ((equalp (nth 0 sp) "Text")
         (format t "
<fields>
    <fullName>~A__c</fullName>
    <externalId>false</externalId>
    <label>~A</label>
    <length>~A</length>
    <required>false</required>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Text</type>
    <unique>false</unique>
</fields>"
             (nth 2 sp)  (nth 1 sp)  (nth 3 sp)))
        ((equalp (nth 0 sp) "TextArea")
         (format t "
<fields>
    <fullName>~A__c</fullName>
    <externalId>false</externalId>
    <label>~A</label>
    <required>false</required>
    <trackFeedHistory>false</trackFeedHistory>
    <type>TextArea</type>
</fields>"
             (nth 2 sp)  (nth 1 sp)))
        ((equalp (nth 0 sp) "Checkbox")
         (format t "
<fields>
    <fullName>~A__c</fullName>
    <externalId>false</externalId>
    <label>~A</label>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Checkbox</type>
</fields>"
             (nth 2 sp)  (nth 1 sp)))
        ((equalp (nth 0 sp) "Picklist")
         (format t "
<fields>
    <fullName>~A__c</fullName>
    <externalId>false</externalId>
    <label>~A</label>
    <picklist>
~{        <picklistValues>
            <fullName>~A</fullName>
            <default>false</default>
        </picklistValues>~%~}        <sorted>false</sorted>
    </picklist>
    <trackFeedHistory>false</trackFeedHistory>
    <type>Picklist</type>
</fields>"
             (nth 2 sp)  (nth 1 sp) (member (nth 3 sp) sp))
         )))))



2013-01-30

Force.com : REST API 開発 ユーザ名パスワード OAuth 認証


※ 更新履歴


  • 2013-03-01:  Authorize.java の JSON データの解析のところを JsonParser から JsonNode 使うように修正した
  • 2016-08-02:  Salesforce による TLS 1.0 の無効化 により、sandbox環境ではJava1.7で実行するとエラーがかえるようになり動かなくなる。javax.net.ssl.HttpsURLConnection 使えってよ



◇ 環境


  • Force.com: Developer Edition version 26.0: Winter'13
  • Java: 1.7.0_11
  • Jackson Java JSON-processor: Jackson-src-1.9.11



◆ ユーザ名パスワード OAuth 認証の仕様


詳細は Understanding the Username-Password OAuth Authentication Flow を参照

■ request body - parameter

□ url

https://login.salesforce.com/services/oauth2/token

□ parameter

パラメータ説明
grant_type「password」
client_idリモートアクセスアプリケーション定義の[コンシューマ鍵]
client_secretリモートアクセスアプリケーション定義の[コンシューマの秘密]
usernameユーザ名
passwordパスワード(セキュリティトークンを付加)

ex.)※ 実際は一行(改行なし)

grant_type=password
&client_id=3MVG9lKcPoNINVBIPJjdw1J9LLM82HnFVVX19KY1uA5mu0QqEWhqKpoW3svG3XHrXDiCQjK1mdgAvhCscA9GE
&client_secret=1955279925675241571
&username=testuser@salesforce.com
&password=mypasswordXXXXXXXXXX


■ response body

□ JSON 形式

パラメータ説明
idユーザ、およびユーザの詳細に関するクエリの両方を識別するために使用できる ID URL
issued_at署名作成日時(秒数)
instance_urlAPIコール送信先SFDCインスタンス
signatureコンシューマの非公開鍵で署名されている Base64 符号化されたHMAC-SHA256 署名
access_tokenアプリケーション要求用セッションIDとして機能するアクセストークン

ex.)※ 実際は一行(改行なし)

{
    "id":"https://login.salesforce.com/id/00Dx0000000BV7z/005x00000012Q9P",
    "issued_at":"1278448832702",
    "instance_url":"https://na1.salesforce.com",
    "signature":"0CmxinZir53Yex7nE0TD+zMpvIWYGb/bdJh6XfOH6EQ=",
    "access_token":"00Dx0000000BV7z!AR8AQAxo9UfVkh8AlV0Gomt9Czx9LjHnSSpwBMmbRcgKFmxOtvxjTrKW19ye6PE3Ds1eQz3z8jr3W7_VbWmEu4Q8TVGSTHxs"
}


■ 考慮事項

このフローではユーザがSalesforceでログインするためにリダイレクトされることはないため、ユーザは直接アプリケーションを認証できません。そのため、更新トークンは使用できません。アプリケーションで更新トークンが必要な場合、Web サーバまたはユーザエージェント OAuth フローの使用を検討してください。

... 考慮事項、何言っているのかよくわかっていない ;-(。



◆ ユーザ名パスワード OAuth 認証 with Java


■ Authorize.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;


public class Authorize {

    /** SFDC:コンシューマ鍵 */
    final static String CLIENT_ID = "(リモートアクセスアプリケーションのコンシューマ鍵)";
    /** SFDC:コンシューマの秘密 */
    final static String CLIENT_SECRET = "(リモートアクセスアプリケーションのコンシューマの秘密)";
    /** SFDC:コールバックURL */
    final static String RESIRECT_URI = "(リモートアクセスアプリケーションのコールバックURL)";
    /** SFDC:ユーザ名 */
    final static String USER_NAME = "(Force.com ユーザ名)";
    /** SFDC:パスワード */
    final static String PASSWORD = "(Force.com パスワード+セキュリティトークン)";    
    /** SFDC:トークン要求 */
    final static String ENVIRONMENT = "https://login.salesforce.com/services/oauth2/token";

    /** Id URL */
    public String id;
    /** 署名作成日時(秒数) */
    public String issued_at;
    /** インスタンスURL */
    public String instance_url;
    /** HMAC-SHA256 署名 */
    public String signature;
    /** アクセストークン */
    public String access_token;

    /**
     * 実行
     * @throws IOException
     */
    public void execute() throws IOException {

        // 接続
        URL url = new URL(ENVIRONMENT);
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        conn.setInstanceFollowRedirects(false);
        conn.setRequestProperty("Accept-Language", "ja");    

        // request body 作成
        Map<String, String> params = new HashMap<String, String>();
        params.put("grant_type", "password");
        params.put("client_id", CLIENT_ID);
        params.put("client_secret", CLIENT_SECRET);
        params.put("username", USER_NAME);
        params.put("password", PASSWORD);
        StringBuilder sb = new StringBuilder();
        for(Iterator<Map.Entry<String, String>> i=params.entrySet().iterator(); i.hasNext(); ) {
            Map.Entry<String, String> entry = i.next();
            String key = entry.getKey();
            String val = entry.getValue();
            sb.append(key).append("=").append(val).append("&");
        }
        if(sb.toString().endsWith("&")) {
            sb = sb.deleteCharAt(sb.length()-1);
        }
        String sParams = sb.toString();

        System.out.println(sParams);

        // request body 送信
        PrintWriter writer;
        writer = new PrintWriter(conn.getOutputStream());
        writer.print(sParams);
        writer.close();

        // response body(json データ)の解析
        StringBuilder json = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            json.append(line);
        }
        reader.close();
        String jsonText = json.toString();

        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readValue(jsonText, JsonNode.class);

        this.id = root.get("id").getTextValue();
        this.issued_at = root.get("issued_at").getTextValue();
        this.instance_url = root.get("instance_url").getTextValue();
        this.signature = root.get("signature").getTextValue();
        this.access_token = root.get("access_token").getTextValue();


        // 切断
        conn.disconnect();
    }
}

コールバック URL にて実行する

// ユーザ名パスワード OAuth 認証
Authorize authorize = new Authorize();
authorize.execute();

これで、アクセストークン取得できた!
が、考慮事項が気になりはじめた今日この頃



◇ 参考





Force.com : REST API 開発


◇ 環境


  • Force.com: Developer Edition Winter'13
  • Java: 1.7.0_11
  • Jackson Java JSON-processor: Jackson-src-1.9.11



◆ SFDC 設定


追記:2013-09-07
※ [作成]→[アプリケーション]から[アプリケーション]画面を表示して、[新規接続アプリケーション]の[新規]から作成するっぽいようになっていた

SFDC の設定

  1. [設定]→[アプリケーションの設定・開発]→[リモートアクセス]より[リモートアクセス]画面を表示する
  2. [リモートアクセスアプリケーション]の[新規]ボタンを押下し、リモートアクセスアプリケーションを指定する
  3. 各内容を設定し[保存]ボタンを押下する
    • アプリケーション: TEST
    • 取引先責任者メール: xxx@xxx.co.jp
    • コールバック URL: http://localhost:9000/ ※ アクセスするシステムの URL

作成した[リモートアクセスアプリケーション](「TEST」)の詳細画面より、下記を確認する(後で使う)

  • コールバック URL
  • コンシューマ鍵
  • コンシューマの秘密



◆ 事前準備


■ 事前準備

Java用のJSON API の標準仕様のライブラリを設定しておく




◆ 実装一覧





◇ 参考





2013-01-25

Mac : Homebrew インストール


◇ 環境


  • OS: MacOS X 10.8.2



◆ 必要条件


  • An Intel CPU
  • OS X 10.5 or higher
  • Command Line Tools for Xcode or Xcode



◆ インストール


homebrew をインストールする

# homebrew のインストール
$ ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"
# *** ログ未取得 ***

# git のインストール
$ brew install git
# *** ログ未取得 ***

$ homebrew のアップデート
$ brew update
# *** ログ未取得 ***



◆ 確認


[brew doctor]コマンドで状態を確認する

$ brew doctor
Warning: You have MacPorts or Fink installed:
  /opt/local/bin/port

This can cause trouble. You don't have to uninstall them, but you may want to
temporarily move them out of the way, e.g.

  sudo mv /opt/local ~/macports
Warning: /usr/bin occurs before /usr/local/bin
This means that system-provided programs will be used instead of those
provided by Homebrew. The following tools exist at both paths:

    git
    git-cvsserver
    git-receive-pack
    git-shell
    git-upload-archive
    git-upload-pack
    gitk

Consider amending your PATH so that /usr/local/bin
occurs before /usr/bin in your PATH.
Warning: Homebrew's sbin was not found in your path.
Consider amending your PATH variable so it contains:
  /usr/local/sbin

… Warning 出てきた

MacPorts 削除する([tree]コマンド欲しかったのでいれてみたのだった brew で入れ直しする

sudo mv /opt/local ~/macports

PATH の設定修正する

$ sudo vi /etc/paths
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
   ↓
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin 
/usr/sbin
/sbin

ターミナルを再起動してもう一回確認

$ brew doctor
Your system is raring to brew.

で、install 成功



◇ 参考





2013-01-23

Playframework : IDE(Eclipse)設定



◇ 環境


  • OS: MacOS X 10.8.2
  • Playframework: 2.0.4
  • Java: 1.7.0_11
  • IDE: Eclipse IDE for Java EE Developers, Juno Service Release 1



◆ Eclipse 設定ファイル生成


[play eclipsify]コマンドを実行し、Eclipse 設定ファイルを生成する

  • 「/Users/username/testapp」サンプルアプリケーションの設定ファイルを生成する
  • play や関連するソースを含める場合は[eclipsify with-source=true]とする ※ 時間かかる

$ cd /Users/username/testapp

$ play

[info] Loading project definition from /Users/username/testapp/project
[info] Set current project to testapp (in build file:/Users/username/testapp/)
       _            _ 
 _ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/ 
             
play! 2.0.4, http://www.playframework.org

> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.

[testapp] $ eclipsify
[info] About to create Eclipse project files for your project(s).
[info] Compiling 4 Scala sources and 2 Java sources to /Users/username/testapp/target/scala-2.9.1/classes...
[info] Successfully created Eclipse project files for project(s):
[info] testapp


  • Play コンソール終了: [Ctr + D]コマンド

ディレクトリ増えている



◆ Eclipse に import


  1. Eclipse を起動する
  2. [File]→[Import]から Import 画面を表示する
  3. [Select]
    1. [General]→[Existing Project into Workspace]を選択する
    2. [Next]ボタンを押下する
  4. [Import Project]
    1. [Select root directory]に「/Users/username/testapp」を設定する
    2. [Finish]ボタンを押下する

Project Explorer に「testapp」が表示されれば OK



◇ 参考





Playframework : サンプルアプリケーション作成



◇ 環境


  • OS: MacOS X 10.8.2
  • Playframework: 2.0.4
  • Java: 1.7.0_11



◆ サンプルアプリケーション作成


[play new]コマンドを実行し、サンプルアプリケーションを作成する

  • 「/Users/username/」ディレクトリ配下に「testapp」と言うサンプルアプリケーションを作成する

$ cd /Users/username/

$ play new testapp
      _            _ 
 _ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/ 
             
play! 2.0.4, http://www.playframework.org

The new application will be created in /Users/username/testapp

What is the application name? 
> testapp

Which template do you want to use for this new application? 

  1 - Create a simple Scala application
  2 - Create a simple Java application
  3 - Create an empty project

> 2

OK, application testapp is created.

Have fun!

ディレクトリ構造を確認する

$tree
.
└── testapp
    ├── README
    ├── app
    │   ├── controllers
    │   │   └── Application.java
    │   └── views
    │       ├── index.scala.html
    │       └── main.scala.html
    ├── conf
    │   ├── application.conf
    │   └── routes
    ├── project
    │   ├── Build.scala
    │   ├── build.properties
    │   └── plugins.sbt
    └── public
        ├── images
        │   └── favicon.png
        ├── javascripts
        │   └── jquery-1.7.1.min.js
        └── stylesheets
            └── main.css



◆ サンプルアプリケーションのテスト起動


[play run]コマンドを実行し、サンプルアプリケーションを実行する

$ cd /Users/username/testapp/

$ play

[info] Loading project definition from /Users/username/testapp/project
[info] Set current project to testapp (in build file:/Users/username/testapp/)
       _            _ 
 _ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/ 
             
play! 2.0.4, http://www.playframework.org

> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.

[testapp] $ run

[info] Updating {file:/username/testapp/}testapp...
[info] Done updating.                                                                  
--- (Running the application from SBT, auto-reloading is enabled) ---

[info] play - Listening for HTTP on port 9000...

(Server started, use Ctrl+D to stop and go back to the console...)
  • サーバ停止: [Ctr + D]コマンド
  • Play 終了: [Ctr + D]コマンド

「http://localhost:9000」へアクセスし、画面が表示されれば OK



◇ 参考





Playframework : インストール手順


◇ 環境


  • OS: MacOS X 10.8.2
  • Playframework: 2.0.4
  • Java: 1.7.0_11



◆ 前提条件


  • JDK 6 以降



◆ インストール


Playframework を DL する


DL した zip を任意の場所(<PLAY_HOME>)に展開する

  • 読み込み / 書き込み権限を有する場所
  • ex.) /Applications/play-2.0.4

パスを設定する

export PATH=$PATH:<PLAY_HOME>

  • パスにスペースを含まない
  • ex.) export PATH=$PATH:/Applications/play-2.0.4



◆ インストール(homebrew)


[homebrew]コマンドで Playframework をインストールする

# デフォルトのバージョンを確認
$ brew info play
play: stable 2.0.4, devel 2.1-RC2, HEAD
http://www.playframework.org/
/usr/local/Cellar/play/2.0.4 (2687 files, 152M) *
https://github.com/mxcl/homebrew/commits/master/Library/Formula/play.rb

# 利用可能なバージョンを確認
$ brew versions play
2.0.4    git checkout 00698a4 /usr/local/Library/Formula/play.rb
2.0.3    git checkout 3c5ca25 /usr/local/Library/Formula/play.rb
2.0.2    git checkout 6ba6dc0 /usr/local/Library/Formula/play.rb
2.0.1    git checkout 15976d5 /usr/local/Library/Formula/play.rb
2.0      git checkout 351d751 /usr/local/Library/Formula/play.rb
1.2.4    git checkout 3caf5c5 /usr/local/Library/Formula/play.rb
1.2.3    git checkout bee9712 /usr/local/Library/Formula/play.rb
1.2.2    git checkout 3137b6a /usr/local/Library/Formula/play.rb
1.2.1    git checkout bcdf2d5 /usr/local/Library/Formula/play.rb
1.2      git checkout 744b044 /usr/local/Library/Formula/play.rb
1.1.1    git checkout 0476235 /usr/local/Library/Formula/play.rb
1.1      git checkout eea40ff /usr/local/Library/Formula/play.rb
1.0.3.1  git checkout aa76115 /usr/local/Library/Formula/play.rb
1.0.3    git checkout 19edb1f /usr/local/Library/Formula/play.rb

# インストール
$ brew install play
==> Downloading http://download.playframework.org/releases/play-2.0.4.zip
Already downloaded: /Library/Caches/Homebrew/play-2.0.4.zip
  /usr/local/Cellar/play/2.0.4: 2646 files, 128M, built in 18 seconds

# アンインストール
$ sudo brew uninstall play
Password: (パスワードを入力)
Uninstalling /usr/local/Cellar/play/2.0.4...



◆ 確認


[play help]コマンドを実行し、起動が確認できれば OK

$ play help
       _            _ 
 _ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/ 
             
play! 2.0.4, http://www.playframework.org

Welcome to Play 2.0!

These commands are available:
-----------------------------
license            Display licensing informations.
new [directory]    Create a new Play application in the specified directory.

You can also browse the complete documentation at http://www.playframework.org.



◇ 参考


Playframework