送信データフローのサポート
Windchill ESI がインストールされている場合、Windchill は送信データフローを可能にする API を ESI モジュールでサポートしています。Blob コンフィギュレーションツールを使用して Azure ストレージアカウントにコンテンツを格納するように Windchill サーバーが設定されており、プロパティ esi.azure.storage.containerwt.properties を介して適切なコンテナ名に設定されている場合、そのコンテナ内の Blob にテキストを書き込むことができます。この API の使用方法の詳細を以下に示します。
パッケージ: com.ptc.windchill.esi.utl
クラス: ESIBlobUtility
メソッド: writeTextToAzureBlob
パラメータ: String blobNameExcludingContainerName, String text
戻り値: true (書き込まれたバイト数が 0 を超える場合)
ネットワーク要件
Windchill 展開がオンプレミスの場合、ストレージアカウントのネットワークコンフィギュレーションで許可リストに Windchill のエグレス IP / CIDR が追加されていることを確認します。
PTC が管理する Windchill 展開の場合、これはすでに処理されています。
Windchill でサポートされている API を使用してこの API を呼び出すことによって、統合のために処理される JSON メッセージを送信できます。このメッセージをさらに Azure BLOB から読み取って、以降の API 呼び出しやその他の統合のために処理できます。
送信データフロー
Azure から ERP 応答ファイルをダウンロードするサンプルアプリケーション
Windchill で、Azure Blob への ESI 応答ファイルの保存がサポートされるようになりました。以降の下流処理のために ESI 応答ファイルを Azure から安全にダウンロードするには、サンプルアプリケーションを参照してください。Windchill では、事前設定された Azure Blob コンテナに ESI 応答ファイルが保存されます。このサンプルアプリケーションの目的は、「ファイル」または「MES」タイプの配布ターゲットに Windchill オブジェクトがパブリッシングされたときに、コンテナに保存されている新規ファイルをチェックしてダウンロードすることです。
1. サンプルコード: ESIResponseDownloader.java:
/* bcwti
*
* Copyright (c) 2023 Parametric Technology Corporation (PTC). All Rights Reserved.
*
* This software is the confidential and proprietary information of PTC
* and is subject to the terms of a software license agreement. You shall
* not disclose such confidential information and shall use it only in accordance
* with the terms of the license agreement.
*
* ecwti
*/

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.models.BlobItem;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobContainerClientBuilder;
import com.azure.storage.blob.specialized.BlobInputStream;
/*
* Class ESIResponseDownloader is used to download blob contents from an azure storage account.
* Provided we have container sas URL from which we need to download the blob contents.
*/
public class ESIResponseDownloader {
public static void main(String[] args) {
String sasURL = System.getenv("CONTAINER_LEVEL_SAS_URL");
String strFetchIntervalInSeconds = System.getenv("FETCHING_INTERVAL_IN_SECONDS");
Long fetchingIntervalInMS = Long.parseLong(strFetchIntervalInSeconds !=null ? strFetchIntervalInSeconds : "300")*1000;
//Get endpoint, containerName and sasToken from SAS URL
String[] urlElements = sasURL.split("/");
// get https://storageaccount.blob.windows.core.net as endpoint
String endPoint = String.join("/", urlElements[0], urlElements[1], urlElements[2], urlElements[3]);
String[] urlElements2 = urlElements[3].split("\\?", 2);
String containerName = urlElements2[0];
String sasToken = urlElements2[1];

//download ESI blobs
while (true) {
try {
downloadESIBlobs(endPoint, containerName, sasToken);
} catch (Exception e) {
System.err.println("Caught an exception! - " + e.getLocalizedMessage() + "\nExiting..");
}
try {
Thread.sleep(fetchingIntervalInMS);
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
}

}
}
/*
* This method will check wheter the files present locally (at path_to_download)
* match list of blob names in a specific folder within container in the storage account or not. If not it
* downloads it locally if the extension of
* file is xml or json.
*
* @param storageAccountUrl Storage account url
* @param containerName Container Name
* @param sasToken SAS Token
*
*/
public static void downloadESIBlobs(String storageAccountUrl, String containerName, String sasToken) {
final String pathToDownload = System.getenv("PATH_TO_DOWNLOAD");
final String logFile = System.getenv("LOG_FILE");
String basePath = Paths.get(pathToDownload, containerName).toString();
// store the list of all blob names present in the esi container
List<String> blobs = listContainerBlobs(storageAccountUrl, containerName, sasToken);
// store the list of all the files present locally
List<String> localFiles = readFromLogFile(logFile);
blobs.forEach(blob -> {
// Check if the blob is already present, if not download it
if(!localFiles.contains(blob)) {
System.out.println(blob + " not present, downloading to " + basePath);
downloadBlob(storageAccountUrl, containerName, blob, sasToken, basePath);
writeToLogFile(blob, logFile);
}
});
}
/*
* This method will return a list of names of all the blobs (with file extension json
* or xml) present in the given container.
* If SUB_FOLDER_PATH environment variable is set then it will look for the
* blobs specific to that folder inside that
* container.
*
* @param storageAccountUrl Storage account url
* @param containerName Container Name
* @param sasToken SAS Token
* @return List of names (full path) of all the blobs present in the container
*/
public static List<String> listContainerBlobs(String storageAccountUrl, String containerName, String sasToken) {
String subFolderPath = System.getenv("SUB_FOLDER_PATH");
List<String> blobList = new ArrayList<>();
BlobContainerClient blobContainerClient = getBlobContainerClient(storageAccountUrl, containerName, sasToken);
for (BlobItem blob : blobContainerClient.listBlobs()) {
if (subFolderPath != null && blob.getName().startsWith(subFolderPath)
&& (blob.getName().endsWith(".xml") || blob.getName().endsWith(".json"))) {
blobList.add(blob.getName());
} else if (subFolderPath == null && (blob.getName().endsWith(".xml") || blob.getName().endsWith(".json"))) {
blobList.add(blob.getName());
}
}
return blobList;
}
/*
* This method reads the log file line by line (whenever a file is downloaded it
* is logged in log file)
* Thus, this method returns the list of names of files present locally.
*
* @param filePath Path to the log file present locally
* @return Returns a list of names of files present locally
*
*/
private static List<String> readFromLogFile(String filePath) {
if (!(new File(filePath).exists())) {
try {
Files.createFile(Paths.get(filePath));
} catch (IOException e) {
e.printStackTrace();
}
}
try {
return Files.readAllLines(Path.of(filePath));
} catch (IOException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
/*
* This method will download Azure blob based on the blob name passed in parameter along with its container name,
* storage account url and SAS token.
* Blob will be downloaded to the blobAbsolutePath and if parentDirectory is not present, it will be created.
*
* @param storageAccountUrl Storage Account Url
* @param containerName Container Name
* @param blobName Full name of the blob which needs to be downloaded
* @param sasToken SAS token
* @param basePath Folder under which we need to download blob contents
*
*/
public static void downloadBlob(String storageAccountUrl, String containerName, String fullBlobName,
String sasToken, String basePath) {
//Creating a blob client to open a Blob Input Stream
BlobClient blobClient = getBlobClient(storageAccountUrl, containerName, fullBlobName, sasToken);
try (BlobInputStream blobIS = blobClient.openInputStream()) {
String blobAbsolutePath = Paths.get(basePath, fullBlobName).toString();
//Check if Parent Directory of Blob (inside the container) is present locally or not. If not create it.
if (!(new File(blobAbsolutePath).exists()))
Files.createDirectories(Paths.get(blobAbsolutePath).getParent());
//Write the blob content to the absolute path locally.
Files.write(Paths.get(blobAbsolutePath), blobIS.readAllBytes());
} catch (Exception e) {
e.printStackTrace();
}
}

/*
* This method writes full blob name to the log file
*
* @param fullBlobName Full blob name
* @param filePath File Path to the log file
*/
private static void writeToLogFile(String fullBlobName, String filePath) {
try {
Files.write(Path.of(filePath), (fullBlobName + System.lineSeparator()).getBytes(StandardCharsets.UTF_8),
StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* This method will get the blob container client which is used for performing
* azure container related operations
*/
public static BlobContainerClient getBlobContainerClient(String storageAccountUrl, String containerName,
String sasToken) {
return new BlobContainerClientBuilder()
.endpoint(storageAccountUrl)
.sasToken(sasToken)
.containerName(containerName)
.buildClient();
}
/*
* This method will get the blob client which is used for performing blob
* related operations
*/
public static BlobClient getBlobClient(String storageAccountUrl, String containerName, String blobName,
String sasToken) {
return getBlobContainerClient(storageAccountUrl, containerName, sasToken).getBlobClient(blobName);
}
}
2. 次の環境変数を設定してから、プロジェクトを構築して実行します。
export PATH_TO_DOWNLOAD= <ダウンロードへのパス>
export LOG_FILE= <ログファイルへのパス>
export FETCHING_INTERVAL_IN_SECONDS= <新規ファイルを再スキャンしてフェッチするまでの時間>
export SUB_FOLDER_PATH= <コンテナ内の特定のフォルダ>
次の値は PTC によって提供されます。
export CONTAINER_LEVEL_SAS_URL= <そのコンテナの共有アクセス署名 URL>
* 
このサンプルは azure-storage-blob ライブラリに依存しています。
これは役に立ちましたか?