2017-10-30

Salesforce: Objects Generalization and Specialization

Salesforce 在設定畫面上的 object 名詞可能是個讓習於物件導向程式開發者困惑的地方:畫面上的 object 代表 type definition,而非 instance,真正描述 instance 的名詞是 record。

然而在處理 generalization & specialization 議題時,畫面上又給了一個新名詞,record type。系統管理者可以把所有可能用到的欄位都開在同一個 object 裡,透過 record type 的方式,限定各個 record type 所能看到的欄位。值得注意的是:這邊的縮限手段,是採用綁定 layout 的方式達成,如果使用 Apex 程式存取,則不在此限。

從 generalization & specialization 的抽象層次來看,record type 確實提供了一種 specialization 的途徑,與物件導向中的 subclass 類似,但很不一樣的是:record type 處理的是資料面的 specialization,讓特定 record type 只能看到原來眾多欄位的子集合,而 subclass 同時兼顧資料面與行為面的 specialization,各個 subclasses 能夠自己額外定義欄位並實作不同行為。

此外,record type 並不像物件導向的繼承關係將共同的部分獨立抽取至 super class,相對於 record types,object 等於是所有欄位的大雜燴,看不到哪些是共同的欄位,對於 generalization 有潔癖的人來說,似乎只能用類似物件導向 composition 的方式處理 [1],也就是 Salesforce 中的 master-detail object relationships [2]

使用 master-detail relationships 實現 generalization 難免有強加物件導向觀念的味道,但更不幸的是:即使採用這麼複雜的設定,仍然無法達成目的。原因在於:使用 master-detail relationships 實作 generalization 時,生命週期控制在 master 端,相當於是 specialized subclass;但在數量對應上 master 端屬於 one-side 而非 many-side,違背 generalization 的初衷。

see also:
[1] Salesforce Developers Forum: Custom Objects and Inheritance
[2] Salesforce Object Relationships

2017-10-24

Apex Serialize Objects to XML

先前的文章 [1] 中提到,Salesforce 的 REST 同時支援兩種輸出格式,XML 與 JSON;client 可以透過 HttpRequst header 中 Accept 屬性指定想要的 content type;這兩個 serialization 的過程對於 REST service 的實作者而言是完全 transparent 的,意即實作時 method 並不 return string 型別,而是直接 return sObject,由系統的 outbound messaging 機制直接處理掉。

然而對於 Apex 開發者而言,程式語言級別對 XML 與 JSON 在 serialization 的支援度就差很遠。以 JSON 為例,無論物件多複雜,要轉成 JSON string 只要一行 JSON.serialize() 就可以搞定 [2],但是轉成 XML string 時,無論使用 XmlStreamWriter [3] 或 DOM.XmlNode [4] [5] 都需要針對物件中各個 fields 作繁瑣地處理。

為了達到快速生成 XML 字串,我們可以透過 (1) 實作一 REST service;(2) 在 Apex 中呼叫該 service,並將 HttpRequest Accept header 設定為 'application/xml' 的方式,快速從 HttpResponse.getBody() 取得 outbound messaging 生成好的 XML 字串。

概念上是走 loopback invocation 的方式,利用既有的機制,寫最少的程式,完成任務。

see also:
[1] Salesforce RESTful Services: Response Content-Type
[2] JSON Support: Roundtrip Serialization and Deserialization
[3] XML Support: Writing XML Using Streams
[4] XML Support: Reading and Writing XML Using the DOM
[5] XmlNode Class
[6] Salesforce Trailblazer Community Idea: Convert Object to XML (Serialize)

.NET: Framework or Virtual Machine

一般提到 .NET 多半使用 .NET framewrok 這個名詞,內容可能包括:
  • Programming Languages: 包括 C#, C++/CLI, F#, IronLisp, IronPython, VB.NET, Powershell 等 [1]
  • Compiler
  • CLI Standard Library: 裡頭主要有 Framework Class Library (FCL) [2] 與 Base Class Library (BCL) [3]
  • Common Intermediate Language (CIL)
  • Common Language Runtime (CLR)
對於傳統使用 C++ 搭配 MFC 開發視窗程式 (GUI desktop application) 的開發者而言,視線會集中在 C# 與 CLI Standard Library;此時 .NET 更趨近於 framework 的角色,提供眾多的 classes,開發人員根據 framework 規範撰寫 component。

然而就 .NET 整體架構來看,最大的改變在於提供了統一的 intermediate language (IL) 介面,使得前端可以同時支援多種程式語言,呼叫同一套 standard library;且這個 IL 設計是獨立於 CPU architecture 與 operating system platform 之外的 [4]。換言之,開發者可以自由地在任何想要的平台上開發 IL 所需的 runtime,因此角色上更接近 virtual machine。

雖然說大多數的 .NET 應用程式都在 Windows 與其內建的 runtime,但還是有不少開發者作過這方面的努力:
但實際使用上,卻不那麼順利。主因在於 .NET 雖然 CIL 提供了優良的隔離,獨立於 Windows 之外,但最重要的 CLI Standard Library 卻因為服務視窗程式開發者的初衷,納入了太多 Windows 特有的 library,尤其是圖形介面 (GDI) 這段,導致許多在 Windows 上開發的元件,無法順利過渡到其它 runtime 執行。

換言之,雖然 CIL 與 CLR 提供了很大 virtual machine 的特點,但身為 runtime infrastructure 重點的 standard library 並未提供相應的設計,導致整個 .NET 回到近乎 Windows 獨有的情況。

這幾年微軟開始改革 Windows Server 的產品線 [8],將圖形介面剝離出來,打破原本 Windows runtime 包山包海的狀況,同時也開始推更乾淨的 .NET Core;就架構而言這應該有助於第三方 .NET runtime 的普及,但微軟將發展 Mono 的 Xamarin 收入麾下卻讓非微軟勢力瞬間消失。

注意:Mono 在 runtime 實作仍是按照舊有的 CLI (ECMA-335) [9] 而非 CoreCLI,因此 Mono 是否會如 .NET Core 壯大仍有很大變數。

此外,Mono 的貢獻在不僅僅於 runtime,還有跨桌面平台的解決方案,這塊的未來應該屬於 Electron [10];至於依賴 Mono runtime 的跨行動平台方案 - Xamarin,個人認為疑慮就很大,目前 Windows Phone 已確定式微,微軟還願意花多少資源給跨行動平台開發方案,看來非常不樂觀。

這兩年微軟也開始引入 LLVM 技術,實作相關的 compiler (LLILC),想要深入這個主題的可以一起參考看看。

see also:
[1] Wikipedia: CLI Languages
[2] Wikipedia: Framework Class Library (FCL)
[3] Wikipedia: Standard Libraries (CLI) 
[4] Wikipedia: Common Intermediate Language (CIL)
[5] Wikipedia: DotGNU
[6] Wikipedia: Protable.NET
[7] Mono Project
[8] Wikipedia: Microsoft Windows Server Core
[9] ECMA-335: Common Language Infrastructure (CLI)
[10] Electron

2017-10-13

SSL Certificate Standards

要搞懂系統認證之前,首先要對非對稱式加密有基礎瞭解,不外乎就 2 種 key:
  • Public key: 用於加密與驗證簽章
  • Private key: 用於解密與產生簽章
至於這兩把 key 的產生通常會由共同信任的第三方,也就是 CA (Certificate Authority) 發出。[1]

Standards: Encoding Rules & Formats

接下來可能會遇到各種檔案,這裡頭牽涉的標準主要有 2 類:
  1. Encoding rule: 說明內容要如何編碼,主要有 DER 與 PEM [2] 兩種,前者的輸出為 binary,後者為 base64。
  2. Message or file format: 定義檔案應該包括那些資訊,主要有 PFX, P12 (PKCS #12), CSR (PKCS #10), X.509
  • PFX 或 P12 (PKCS #12) [3]: 也就是 CA-signed certificate;這類檔案帶有 private key,一般會被保護起來,很少複製傳遞。
  • CSR (PKCS #10) [4]: Certificate Signing Request; 為 client 向 CA 要求簽發憑證時使用,帶自身站台資訊,最少使用。
  • X.509 [6] 或 P7C (PKCS #7) [7]: 最常見,用於存放 public certificate 或 signature,其中 P7C 預定為 BER encoding,因此不會與其它 encoding rule 併用。
File Name Extensions

上頭這些標準名稱都常見於副檔名,譬如說:
  •  *.pfx 與 *.p12 一定是 CA-signed certificate,未指定 encoding rule,但通常為 binary,可與 PEM 合併使用。
  •  *.p7c 一定是 public certificate,固定為 BER encoding。
  •  *.der 與 *.pem 通常僅為 public certificate,用副檔名描述編碼方式。
除此,*.cer 與 *.crt 也是常見的副檔名,大多也僅為 public certificate,可套用任何 encoding rule。

最後是這些 key 如何被保存到 client 與 server;對系統來說,存放位置分為 TrustStore 或 KeyStore,分別存放扮演 consumer 與 provider 時,使用的 public certificate 與 private keys。
  • 與一般 symmetric authentication 所稱的 certificate 一詞不同,symmetric authentication 中的 certificate 多半為 username/password,但這邊的 certificate 泛指 signature 或包含 private key。
  • 例如:CA-signed certificate 即為兩者組合,而 public certificate 則為 signature。所以當單純看到副檔名 *.crt 或 *.cer,並無法確定內容是否包括 private key,類似的情況也發生在 *.pem 的檔案。

ps. Java 的 KeyStore 副檔名通常為 *.jks,由於 KeyStore 用來存放 CA-signed certificate 的關係,有些系統便使用 Java KeyStore 檔取代 *.pfx 或 *.p12,作為匯入 CA-signed certificate 時使用。


see also:
[1] Public Key Infrastructure
[2] PEM (Privacy-enhanced Electronic Mail): Base64 encoded DER certificate
[3] PKCS #12: Personal Information Exchange Syntax Standard
[4] CSR (Certificate Signing Request)
[5] PKCS (Public Key Cryptography Standards)
[6] X.509
[7] PKCS #7: Cryptographic Message Syntax
[8] DER vs. CRT vs. CER vs. PEM Certificates and How To Convert Them


Salesforce RESTful Services: Publish

當使用 Salesforce 作為 API provider 時,預設採用 OAuth 2.0 作為認證機制,如果想簡化認證過程,則可透過將 API 發佈到公開站台的方式完成,此時需要針對 site profile 進行設定。
  • 首先要進到 site details page;在 Setup / Build / Develop / Sites,點選 Site Label 欄位 (不是 Edit 也不是 Site URL)。
  • Site Details page 上方有個 Public Access Settings button,點進去後可能會因為 Org 不同而出現不同畫面:
  • Personal Develop Org: 畫面為一個很長的表格,要設定的地方有:Enabled Apex Class Access, Field-Level Security 與 Object Permissions。
  • Production Sandbox Org: 分成 Apps 與 System 兩段,需設定的連結落在 Apps 裡頭,分別是 Apex Class Access 與 Object Settings。
設定的重點不外乎:service class 本身以及相關需要存取的物件欄位,因此只要分別在 Apex Class 與 Objects 中將相關權限打開即可。

see also:
[1] Public RESTful Web Services on Force.com Sites
[2] Public Access Settings for Force.com Sites
[3] Public Access Settings in Salesforce

Salesforce RESTful Services: Response Content-Type

Salesforce 實作 RESTful 時,不需額外的程式碼,系統會自動支援 2 種 response Content-Type:JSON 與 XML。

但由於回傳 XML 時,內部的 tag 名稱會代出自訂欄位與物件的名稱,並不存在於 W3C 預設 namespace 中,而 Salesforce 亦不會代為產生對應的 XML schema,因此對於某些 XML parser 來說會造成 parsing error,比較直覺的解法是繞過回傳 XML 改使用 JSON。

ps. 實際測試時,回傳的 XML 字串會設定 namespace 為 http://soap.sforce.com/schemas/class/ 開頭的 URL,但並未實際生成 XML schema。

前面說過 Salesforce 會自動支援 2 種 response Content-Type,切換的依據是根據 request header 中的 Accept 屬性。
  • 一般瀏覽器 (Chrome, Firefox, IE) 預設的 Accept Content-Type 為 text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8,此時 Salesforce 會優先取用 application/xml
  • 當未設定 Accept Content-Type,或指定 Accept Content-Type 為 application/json 或空白時,Salesforce 預設會以 JSON 作為 response Content-Type。
如果想直接在 server 端指定只支援 JSON,則必須將 method 的 return type 改為 void,並自行指定 HttpResponse,填入 JSON 字串。

RestContext.response.addHeader('Content-Type', 'application/json');
RestContext.response.responseBody = Blob.valueOf('{ "result": true}');

ps. 回傳的 charset 預設皆為 UTF-8,不需要額外設定 Accept-Charset。

see also:
[1] Apex REST Methods
[2] How can I return JSON object from REST service?

2017-10-06

Apex Describe Information

Salesforce 針對 SObject 與 field 分別提供相關的 describe information (a.k.a. metadata),有點類似 Java 中的 java.lang.reflect.Type 與 java.lang.reflect.Field;不過 Salesforce 進一部拆分成 token 與 describe result,前者為一個 compile-time generated & runtime immutable reference,沒有細部資料,但可用於比對 (==),而後者才是真正具備細部資料的結構。

  • Token 轉換至 describe result 的行為稱之為 describe,呼叫 getDescribe() method,可視為 dereference & data loading。
  • SObject 與 field 的 token 與 describe result 資料型別與相關取用方式分別為:
下圖為 4 種 describe information 的產生與轉換方式:
  • 除了 SObject 的 token 與 describe result 有機會從 instance 取得,其餘都必須在 Apex code 中指定 SObject 或 Field name 才能獲得。
  • 不只 SObject instance 有提供 getSObjectType() method,其它提供此 method 的還包括:SObject Describe Result, List 與 Map;其中 List 與 Map 呼叫 getSObjectType() 時等同於針對其 element instance 呼叫該 method。

see also:
[1] Apex Developer Guide: Schema Class
[2] Apex Developer Guide: Schame Namespace
[3] Apex Developer Guide: Dynamic Apex