Adobe PDF Services #NonPDF: Create PDF

Adobe PDF Services #Results: Download

translate Adobe PDF Services #成果物: ダウンロード

Downloads the files (results of PDF OPERATIONS) from PDF Services storage using Polling-URI; Job status URI for polling the results. Note that if the Job is in progress, the FILE type data will be updated as empty, and errors will not occur.

Auto Step icon
Configs for this Auto Step
AuthzConfU1
U1: Select Authz for PDF-SERVICES-API Client ID (Fixed Value) *
AuthzConfU2
U2: Select Authz for PDF-SERVICES-API Client Secret (FixedValue) *
StrConfA1
A1: Set Polling-URI *#{EL}
SelectConfB0
B0: Select STRING that stores Job Status (update)
SelectConfB1
B1: Select FILE that stores Result Files (update)
StrConfU3
U3: Set {regionCode} to process in a specified region (“ew1”)#{EL}
SelectConfB1b
B1b: Select FILE that stores Result Files (append)
SelectConfB2
B2: Select STRING that stores AssetID(s) (update)
SelectConfB3
B3: Select STRING that stores DownloadUri(s) (update)
StrConfC1
C1: To save-as, Set new File Name(s)#{EL}
Script (click to open)
// Script Example of Business Process Automation
// for 'engine type: 3' ("GraalJS standard mode")
// cf. 'engine type: 2' ("GraalJS Nashorn compatible mode") (renamed from "GraalJS" at 20230526)

//////// START "main()" /////////////////////////////////////////////////////////////////

main();
function main(){ 

////// == Config Retrieving / 工程コンフィグの参照 ==
const strAuthzId          = configs.get( "AuthzConfU1" );       /// REQUIRED
  engine.log( " AutomatedTask Config: Authz ID: " + strAuthzId );
  const strClientId       = httpClient.getOAuth2Token( strAuthzId );
  if (  strClientId     === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {U1: ClientId} is empty \n" );
  }
const strAuthzSecret      = configs.get( "AuthzConfU2" );       /// REQUIRED
  engine.log( " AutomatedTask Config: Authz SECRET: " + strAuthzSecret );
  const strClientSecret   = httpClient.getOAuth2Token( strAuthzSecret );
  if (  strClientSecret === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {U2: ClientSecret} is empty \n" );
  }
const strRegionCode       = configs.get( "StrConfU3" );         // Not Required
  let strRegionPostfix    = strRegionCode !== "" ? ("-" + strRegionCode) : "";
  engine.log( " AutomatedTask Config: strRegionPostfix: " + strRegionPostfix );
  // https://developer.adobe.com/document-services/docs/overview/pdf-services-api/howtos/service-region-configuration-for-apis/
const strPollingUri       = configs.get( "StrConfA1" );         /// REQUIRED

const filesPocketUpdate = configs.getObject( "SelectConfB1" ); // NotRequired
  let filesUpdate       = new java.util.ArrayList();
const filesPocketAppend = configs.getObject( "SelectConfB1b" ); // NotRequired
  let filesAppend       = new java.util.ArrayList();
  if ( filesPocketAppend !== null ) {
    if ( engine.findData( filesPocketAppend ) !== null ) {
      filesAppend       = engine.findData( filesPocketAppend ); // java.util.ArrayList
      engine.log( " AutomatedTask FilesArray {B1b}: " +
                  filesAppend.size() + " files" );
    }
  }
const strPocketStatus      = configs.getObject( "SelectConfB0" );  // Not Required
const strPocketAssetIds    = configs.getObject( "SelectConfB2" );  // Not Required
const strPocketDownUris    = configs.getObject( "SelectConfB3" );  // Not Required
let   strSaveAss           = configs.get( "StrConfC1" );           // NotRequired


////// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)



////// == Calculating / 演算 ==

//// Adobe Developer > PDF Services API > Generate Token
//// Generate access token to perform PDF Services operations
//// https://developer.adobe.com/document-services/docs/apis/#tag/Generate-Token

/// prepare request1
let request1Uri = "https://pdf-services" + strRegionPostfix + ".adobe.io/token";
let request1 = httpClient.begin(); // HttpRequestWrapper
/// prepare application/x-www-form-urlencoded
    request1 = request1.formParam ( "client_id",     strClientId );
    request1 = request1.formParam ( "client_secret", strClientSecret );

/// try request1
const response1     = request1.post( request1Uri ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest1 Start: " + request1Uri );
const response1Code = response1.getStatusCode() + ""; // JavaNum to string
const response1Body = response1.getResponseAsString();
engine.log( " AutomatedTask ApiResponse1 Status: " + response1Code );
if( response1Code !== "200"){
  throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
                    response1Code + "\n" + response1Body + "\n" );
}
/* engine.log( response1Body ); // debug
{
  "access_token":"xxxxxxxxxx975yyyyyyyyyy",
  "token_type":"bearer",
  "expires_in":86399
}
*/

/// parse response1 (OAuth Server-to-Server)
const response1Obj = JSON.parse( response1Body );
const strAccessToken = response1Obj.access_token;


//// Adobe Developer > PDF Services API
//// default poll
//// - $.status  // "in progress"(200), "done"(200), "failed"(500)
//// - $.asset.metadata.type
//// - $.asset.downloadUri
//// - $.asset.assetID
//// https://developer.adobe.com/document-services/docs/apis/#tag/Split-PDF/operation/pdfoperations.splitpdf.jobstatus
//// Poll the split pdf job for completion / Poll the pdf to image job for completion
//// - $.status
//// - $.assetList[i].metadata.type
//// - $.assetList[i].downloadUri
//// - $.assetList[i].assetID
//// 
//// Not supported: Poll the accessibility auto-tag job for completion / Poll the extract pdf job for completion / PDF Properties

/// prepare request2
let request2Uri = strPollingUri;
let request2 = httpClient.begin(); // HttpRequestWrapper
/// prepare header parameters
    request2 = request2.bearer ( strAccessToken );
    request2 = request2.header ( "x-api-key", strClientId );

/// try request2
const response2     = request2.get ( request2Uri ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest2 Start: " + request2Uri );
const response2Code = response2.getStatusCode() + ""; // JavaNum to string
const response2Body = response2.getResponseAsString();
engine.log( " AutomatedTask ApiResponse2 Status: " + response2Code );
if( response2Code !== "200"){
  throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
                    response2Code + "\n" + response2Body + "\n" );
}
/* engine.log( response2Body ); // debug
{
  "status":"done",
  "asset":{
    "metadata":{
      "type":"application/pdf",
      "size":77322
    },
    "downloadUri":"https://dcplatformstorageservice-prod-us-east-1.s3-accelerate.amazonaws.com/xxxxx838yyyyy",
    "assetID":"urn:aaid:AS:UE1:582675cc-f871-46ab-a21d-fb3ca0e76558"
  }
}
*/

/// parse response2
const response2Obj   = JSON.parse( response2Body );
const strStatus      = response2Obj.status;
engine.log( " AutomatedTask: PDF-Job Status: " + strStatus );
if ( strStatus === "in progress" ) {
  if( strPocketStatus !== null ){
    engine.setData( strPocketStatus,   strStatus );
  }
  if( filesPocketUpdate !== null ){
    engine.setData( filesPocketUpdate, filesUpdate );
  }
  return 0; 
}
if ( strStatus === "failed" ) {
  throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
                    response2Code + " (failed)\n" + response2Body + "\n" );
}

let numAssets   = response2Obj.assetList?.length ?? 1;
let arrAssetIds = [];
let arrDownUris = [];
let arrConTypes = [];

if ( "content" in response2Obj && "resource" in response2Obj ){ // case "Extract PDF"
  numAssets = 2;
  arrConTypes.push ( response2Obj.content.metadata.type );
  arrDownUris.push ( response2Obj.content.downloadUri );
  arrAssetIds.push ( response2Obj.content.assetID );
  arrConTypes.push ( response2Obj.resource.metadata.type );
  arrDownUris.push ( response2Obj.resource.downloadUri );
  arrAssetIds.push ( response2Obj.resource.assetID );
} else if ( numAssets === 1 ){
  arrConTypes.push ( response2Obj.asset.metadata.type );
  arrDownUris.push ( response2Obj.asset.downloadUri );
  arrAssetIds.push ( response2Obj.asset.assetID );
} else {
  for ( let i = 0; i < numAssets; i++ ) {
    arrConTypes.push ( response2Obj.assetList[i].metadata.type );
    arrDownUris.push ( response2Obj.assetList[i].downloadUri );
    arrAssetIds.push ( response2Obj.assetList[i].assetID );
  }
}

let arrSaveAss = [];
if ( strSaveAss !== "" ){ 
  arrSaveAss = strSaveAss.split ('\n');
}


const numHttpLimit = httpClient.getRequestingLimit(); // `10` asof 202308
if ( numAssets > numHttpLimit - 2 ){
  numAssets = numHttpLimit - 2;
}

//// GET API call [i]
// Downloading the asset
// https://developer.adobe.com/document-services/docs/overview/pdf-services-api/gettingstarted/#step-5--downloading-the-asset

for ( let i = 0; i < numAssets; i++ ) {
  /// prepare request3
  let request3Uri = arrDownUris[i];
  let request3 = httpClient.begin(); // HttpRequestWrapper
  /// try request3
  const response3     = request3.get ( request3Uri ); // HttpResponseWrapper
  engine.log( " AutomatedTask ApiRequest3 Start: " + request3Uri );
  const response3Code = response3.getStatusCode() + ""; // JavaNum to string
  engine.log( " AutomatedTask ApiResponse3 Status: " + response3Code );
  if( response3Code !== "200"){
    throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
                      response3Code + "\n" + response3.getResponseAsString() + "\n" );
  }

  let strTmp = arrSaveAss?.[i] ?? processInstance.getProcessInstanceId().toString() + "-" + i;
    if ( i === 0 ){
      strTmp = arrSaveAss?.[i] ?? processInstance.getProcessInstanceId().toString();
    }
      strTmp = user_correctFileExtension ( strTmp, arrConTypes[i] );

  const qfileTmp = new com.questetra.bpms.core.event.scripttask.NewQfile(
    strTmp, response3.getContentType(), response3.getResponse()
  );
  filesUpdate.add( qfileTmp );
  filesAppend.add( qfileTmp );
}


////// == Data Updating / ワークフローデータへの代入 ==

if( strPocketStatus !== null ){
  engine.setData( strPocketStatus,   strStatus );
}
if( filesPocketUpdate !== null ){
  engine.setData( filesPocketUpdate, filesUpdate );
}
if( filesPocketAppend !== null ){
  engine.setData( filesPocketAppend, filesAppend );
}
if( strPocketAssetIds !== null ){
  engine.setData( strPocketAssetIds, arrAssetIds.join('\n') );
}
if( strPocketDownUris !== null ){
  engine.setData( strPocketDownUris, arrDownUris.join('\n') );
}

} //////// END "main()" /////////////////////////////////////////////////////////////////


// Get the default extension for a content-type (PDF Services targetFormat)
/**
 * Corrects the file extension of the provided save-as name, returns a resultant save-as name with correct extension.
 * If the save-as name does not end with an extension, it appends the correct one according to the MIME type of the content.
 *
 * @param {string} strSaveAs - The name to save the file as. Can be with or without extension.
 * @param {string} strContentType - The MIME type of the content. For example, "application/pdf", "image/jpeg", etc.
 *
 * @returns {string} A corrected save-as name with the correct extension, if needed, according to the content type.
 *
 * @example
 * // returns 'document.pdf'
 * user_correctFileExtension('document', 'application/pdf')
 * 
 * @example
 * // returns 'image.jpg'
 * user_correctFileExtension('image', 'image/jpeg')
 * 
 * @example
 * // returns 'image.jpg' - although 'png' is provided, but jpg image type is given, so it corrects the extension
 * user_correctFileExtension('image.png', 'image/jpeg')
 */
function user_correctFileExtension ( strSaveAs, strContentType ){
  const objMime2Extension = {
    'application/json': '.json',
    'application/pdf': '.pdf',
    'text/html': '.htm',
    'application/zip': '.zip',
    'image/bmp': '.bmp',
    'application/msword': '.doc',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx',
    'image/gif': '.gif',
    'image/jpeg': '.jpg',
    'image/png': '.png',
    'application/vnd.ms-powerpoint': '.ppt',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation': '.pptx',
    'application/rtf': '.rtf',
    'image/tiff': '.tif',
    'text/plain': '.txt',
    'application/vnd.ms-excel': '.xls',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx'
  };

  let strExtension = objMime2Extension?.[ strContentType ] ?? "";
  if ( ! strSaveAs.endsWith( strExtension ) ){
    strSaveAs += strExtension;
  }
  return strSaveAs;
}


/*
Notes:
- If you place this "Automated Step" in the Workflow diagram, the request will be automatically sent every time the process token arrives.
    - A request is automatically sent to the Adobe PDF Services API server. (REST API)
    - The response from the Adobe PDF Services API server is automatically parsed.
- This "Automated Step" will automatically download the file (Asset) stored in Adobe's internal storage.
    - Default file name is process id.
         - Filename extensions (.pdf, etc.) are autocompleted.
    - In addition to the result files, the Download-URI and AssetID can also be acquired.
- To activate a Workflow App that includes this Automated Step, "HTTP Authz Setting" is required
    - Set Credentials to "Token Fixed Value" in Workflow App.
    - Obtain Credentials ("Client ID" and "Client Secret") in advance.
        - https://acrobatservices.adobe.com/dc-integration-creation-app-cdn/main.html?api=pdf-services-api
    - Adobe Developer Console
        - https://developer.adobe.com/console/projects
- "Results" will be available for download after a certain amount of time.
    - If the job status is `done`, they will be downloaded.
    - If the job status is `in progress`, they can not be downloaded.
        - The FILE type data is updated empty.
    - Place this Automatated Step in the loop flow.
        - Or place it in a position where enough time has passed.

APPENDIX
- PDF Services: 
    - Essential PDF tools to store and share files online, as well as create, combine, export, organize, and fill & sign documents.
    - https://helpx.adobe.com/enterprise/using/optional-services.html
- PDF Services API to automate for your document workflows
    - create a PDF from a dynamic HTML report
    - set a password to prevent unauthorized opening of the document
    - compress it for sharing as an attachment
    - extract text, tables, images and document structure to enable downstream solutions
    - https://developer.adobe.com/document-services/docs/overview/#pdf-services-api-to-automate-for-your-document-workflows
- Adobe PDF Services API Free Tier
    - 500 freeDocument Transactions per month. No credit card required. (asof 202306)
    - https://developer.adobe.com/document-services/docs/overview/limits/#usage-limits
- Internal storage retention period
    - Each ASSET is deleted after a certain period of time.
    - AutomatedTask UnexpectedResponseError: 404
    - `{"error":{"code":"Not Found","message":"The requested resource does not exist."}}`
- Enhanced backward compatibility from "adobe-pdf-services-results-download-2023"
    - Supports Job status storage (B0)
        - To make loop flow easier
        - "B0: Select STRING that stores Job Status (update)"
    - Corresponds to the limit number of HTTP requests (10 times: as of 202308)
        - Files that exceed the limit of the add-on automated step are not downloaded (8 files: as of 202308)
    - Supports "Extract PDF":
        - Get JSON and ZIP

Notes-ja:
- この[自動工程]をワークフロー図に配置すれば、案件が到達する度にリクエストが自動送信されます。
    - Adobe PDF Services API サーバに対してリクエストが自動送出されます。(REST API通信)
    - Adobe PDF Services API サーバからのレスポンスが自動保存解析されます。
- この[自動工程]は、Adobe 内部ストレージに保存されている成果物ファイルを自動ダウンロードします。
    - Defaultファイル名はプロセスIDです。
        - ファイル名の拡張子(.pdf等)は自動補完されます。
    - 成果物ファイル以外に、ファイルの Download-URI AssetID も取得可能です。
- この[アドオン自動工程]を含むワークフローアプリを運用するには[HTTP 認証設定]が必要です。
    - Credentials はワークフローアプリの[トークン直接指定]にセットします。
    - あらかじめ Credentials ("Client ID" および "Client Secret") を取得しておいてください。
        - https://acrobatservices.adobe.com/dc-integration-creation-app-cdn/main.html?api=pdf-services-api
    - Adobe Developer Console
        - https://developer.adobe.com/console/projects
- "成果物" は、一定時間経過後にダウンロードできるようになります。
    - Jobステータスが `done` になっていればダウンロードされます。
    - Jobステータスが `in progress` の間は、ダウンロードされません。
        - ファイル型データは空で更新されます。
    - この[自動工程]の典型的な利用方法としては、ループ構造の中に配置します。
        - もしくは、十分な時間経過が担保される位置に配置します。

APPENDIX-ja
- PDF Servicesとは
    - ファイルのオンラインでの保存、共有のほか、ドキュメントの作成、結合、書き出し、整理、入力と署名を行うための PDF 基本ツールです。
    - https://helpx.adobe.com/jp/enterprise/using/optional-services.html
- Document ワークフローを自動化する PDF Services API
    - 動的 HTML レポートから PDF を簡単に作成
    - ドキュメントが不正に開かれないようにパスワードを設定
    - 添付ファイルとして共有するために圧縮
    - テキスト、表、画像、ドキュメント構造を抽出してダウンストリーム ソリューションを実現
    - https://developer.adobe.com/document-services/docs/overview/#pdf-services-api-to-automate-for-your-document-workflows
- Adobe PDF Services API の無料利用枠
    - 毎月500件の無料ドキュメントトランザクション。クレジットカードは必要なし。(202306現在)
    - https://developer.adobe.com/document-services/docs/overview/limits/#usage-limits
- 内部ストレージの保存期間
    - 各ASSETは、一定時間経過で削除されます。
    - AutomatedTask UnexpectedResponseError: 404
    - `{"error":{"code":"Not Found","message":"The requested resource does not exist."}}`
- 下位互換エンハンス(from "adobe-pdf-services-results-download-2023")
    - Jobステータス格納(B0)に対応
        - ループFlowを組みやすくするため
        - "B0: Jobステータスが格納される文字列型データ項目を選択してください (更新)"
    - HTTPリクエスト数上限に対応(10回:202308現在)
        - アドオン自動工程の制限値を超えるファイルはダウンロードしない(8ファイル:202308現在)
    - "Extract PDF" に対応:
        - JSON と ZIP の取得
        - `https://developer.adobe.com/document-services/docs/apis/#tag/Extract-PDF/operation/pdfoperations.extractpdf.jobstatus`
*/

Download

warning Freely modifiable JavaScript (ECMAScript) code. No warranty of any kind.
(Installing Addon Auto-Steps are available only on the Professional edition.)

Notes

  • If you place this “Automated Step” in the Workflow diagram, the request will be automatically sent every time the process token arrives.
    • A request is automatically sent to the Adobe PDF Services API server. (REST API)
    • The response from the Adobe PDF Services API server is automatically parsed.
  • This “Automated Step” will automatically download the file (Asset) stored in Adobe’s internal storage.
    • Default file name is process id.
      • Filename extensions (.pdf, etc.) are autocompleted.
    • In addition to the result files, the Download-URI and AssetID can also be acquired.
  • To activate a Workflow App that includes this Automated Step, “HTTP Authz Setting” is required
  • “Results” will be available for download after a certain amount of time.
    • If the job status is done, they will be downloaded.
    • If the job status is in progress, they can not be downloaded.
      • The FILE type data is updated empty.
    • Place this Automatated Step in the loop flow.
      • Or place it in a position where enough time has passed.

Capture

Adobe PDF Services #Results: Download

Appendix

  • PDF Services:
  • PDF Services API to automate for your document workflows
  • Adobe PDF Services API Free Tier
  • Internal storage retention period
    • Each ASSET is deleted after a certain period of time.
    • AutomatedTask UnexpectedResponseError: 404
    • {"error":{"code":"Not Found","message":"The requested resource does not exist."}}
  • Enhanced backward compatibility from “adobe-pdf-services-results-download-2023”
    • Supports Job status storage (B0)
      • To make loop flow easier
      • “B0: Select STRING that stores Job Status (update)”
    • Corresponds to the limit number of HTTP requests (10 times: as of 202308)
      • Files that exceed the limit of the add-on automated step are not downloaded (8 files: as of 202308)
    • Supports “Extract PDF”:
      • Get JSON and ZIP

See Also

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: