支持出站数据流
安装 Windchill ESI 后,Windchill 支持将 API 用于 ESI 模块,以允许访问出站数据流。如果使用 Blob 配置工具将 Windchill 服务器配置为将内容存储在 Azure Storage 帐户上,并且通过 wt.properties 将特性 esi.azure.storage.container 设置为相应的容器名称,则可以将文本写入该容器内的 Blob。以下是有关此 API 的使用方法的详细信息。
包:com.ptc.windchill.esi.utl
类:ESIBlobUtility
方法:writeTextToAzureBlob
参数:String blobNameExcludingContainerName, String text
返回:true (如果写入的字节数大于 0)
网络要求
• 如果 Windchill 部署是本地部署,请确保存储帐户网络配置在允许列表中添加了 Windchill 的出口 IP/CIDR。
• 对于由 PTC 管理的 Windchill 部署,已执行此操作。
通过调用此 API,可以使用 Windchill 支持的 API 发送 JSON 消息,以便进行集成处理。此消息可进一步从 Azure Blob 读取和处理,进而调用 API 或其他集成。
从 Azure 下载 ESI 响应文件的示例应用程序
Windchill 现支持将 ESI 响应文件存储到 Azure Blob 中。有关更多下游处理信息,请参阅“从 Azure 安全下载 ESI 响应文件的示例应用程序”。Windchill 将 ESI 响应文件存储在预配置的 Azure Blob 容器中。此示例应用程序旨在将 Windchill 对象发布到“文件”或 MES 类型的分布目标时,检查并下载存储在容器中的新文件。
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 库。 |