IM-PDFCoordinator for Accel Platform プログラミングガイド 第12版 2023-10-01

4. プログラミング

4.1. 動作概念

通常の JavaEE開発モデル ・ スクリプト開発モデル プログラムは、ApplicationRuntime で実行されます。

IM-PDFCoordinator for Accel Platform で提供されるAPI も、ApplicationRuntime で動作します。

詳しくは、APIリストをご覧ください。

4.2. APIの種類と性質

IM-PDFCoordinator for Accel Platform は、次のAPIを用意しています。

  • JavaEE開発モデル で利用可能なJava-API(クラス)
  • スクリプト開発モデル で利用可能なスクリプトAPI(クラス)

4.3. プログラム開発における注意点

4.3.1. PDFファイルへのアクセス

IM-PDFCoordinator for Accel Platform が提供するAPIで加工・編集前後のファイルのパスを指定する際には、AppRuntimeからアクセス可能なパスを指定してください。

加工・編集するPDFファイルのサイズによっては、ネットワーク、APIのレスポンス、PDFファイルの編集が完全に終了するタイミングが大きく異なる場合があります。

特にサイズの大きいPDFファイルを加工・編集する場合は、十分な時間が経過した後に加工・編集したPDF ファイルにアクセスするようにしてください。

4.3.2. PDFファイルの事前チェック

外部から不特定のPDFファイルが投入されるシステムでは、サーバの安定運用の点からPDFファイルの事前チェックを推奨します。

これは、PDFファイルに問題がないかチェックをすることで、サーバに害を与えるPDFファイルを事前にはじくことが目的です。

以下のサンプルでは、PDF結合処理を実行し正常終了するか確認をしています。

PDF事前チェックを exe で処理するのは、何か問題が発生した際に影響範囲をこのプロセス内に抑えるためです。

以下にサンプルを記載します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * PDFファイルの結合処理を実行し、元ファイルに問題があるか判定します。
 * サーバに悪影響を与えるファイルを事前にはじくことが目的です。
 * 本ソースは、利用方法の説明のためのサンプルですのでサポート対象です。
 * @version 1.0
 */
public class pdfcheck {

	private static final int STATUSCODE_SUCCESS = 0;
	private static final int STATUSCODE_MESSAGE_WITHOUT_ERRORCODE = -9990;
	private static final int STATUSCODE_EXCEPTION = -9991;
	private static final int STATUSCODE_INVALID_ARGS = -9992;

	private static class CheckResults {
		 // 初期値として、ステータスコードに成功時の値/メッセージに空文字を設定
		 int code = STATUSCODE_SUCCESS;
		 String message = "";
	}

	/**
	 * ypdfcomb.exeを実行して元ファイルに問題があるかどうかチェックします。
	 * @param infile 元ファイル
	 * @param pwd パスワード
	 */
	public static CheckResults execute(String infile, String pwd) {
		CheckResults checkResults = new CheckResults();

		try {
			// 出力先となる一時ファイルの作成
			File outfile = File.createTempFile("pdfcheck_", ".pdf");
			// プログラム終了時に一時ファイルを自動削除するように設定
			outfile.deleteOnExit();

			List<String> command = getCommandList(infile, outfile.getPath(), pwd);

			ProcessBuilder processBuilder = new ProcessBuilder(command);
			// 標準エラーを標準出力にマージ
			processBuilder.redirectErrorStream(true);
			Process process = processBuilder.start();

			try (InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
				String line;
				StringBuilder message = new StringBuilder();
				while ((line = bufferedReader.readLine()) != null) {
					message.append(line);
				}

				// エラー発生時は標準出力からコードとメッセージを取得する
				if (process.waitFor() != 0) {
					checkResults.code = getErrorCode(message.toString());
					checkResults.message = getErrorMessage(message.toString());
				}
			}
		}
		catch (IOException | InterruptedException | NumberFormatException | SecurityException e) {
			// 例外についてはエラーコードを取得することができないため、固定の数値を返す
			e.printStackTrace();
			checkResults.code = STATUSCODE_EXCEPTION;
			checkResults.message = e.getMessage();
		}

		return checkResults;
	}

	/**
	 * 実行用のコマンドを返す。
	 * @param infile 元ファイル
	 * @param outfile 出力ファイル
	 * @param pwd パスワード
	 * @return コマンド
	 */
	private static List<String> getCommandList(String infile, String outfile, String pwd) {
		List<String> command = new ArrayList<String>();
		command.add("ypdfcomb");
		// エラー発生時、メッセージが表示されるように設定
		command.add("-se");
		command.add("y");
		// チェック後、出力されるPDFファイルを設定
		command.add("-o");
		command.add(outfile);
		// PDF連結時の作業フォルダとして、システムのデフォルト一時フォルダを設定
		command.add("-temp");
		command.add(System.getProperty("java.io.tmpdir"));

		// パスワードの有無で引数を分岐
		if (Objects.isNull(pwd) || pwd.isEmpty()) {
			// チェックを行うPDFを設定
			command.add("-i");
			command.add(infile);
		} else {
			// チェックを行うPDF、およびパスワードを設定
			command.add("-ip");
			command.add(infile);
			command.add(pwd);
		}

		return command;
	}

	/**
	 * 標準出力に出力されるエラーメッセージからエラーコード部分を取得します。
	 * メッセージの書式は以下の通りです。
	 * [エラーコード]:エラーメッセージ[備考]
	 * @param message 標準出力
	 * @return エラーコード
	 */
	private static int getErrorCode(String message) throws NumberFormatException {
		// エラーメッセージからエラーコードが取得できなかった場合は、固定の数値を返す
		int sts = STATUSCODE_MESSAGE_WITHOUT_ERRORCODE;

		// エラーメッセージ全体を取得する正規表現のうち、
		// エラーコード部分を正規表現グループ1とする
		Pattern pattern = Pattern.compile("\\[(\\d*)\\]:.*");
		Matcher matcher = pattern.matcher(message);

		if (matcher.find() && matcher.groupCount() >= 1) {
			// 正規表現グループ1(エラーコード部分)を取得
			sts = Integer.parseInt(matcher.group(1));
		}

		return sts;
	}

	/**
	 * 標準出力に出力されるエラーメッセージから、
	 * エラーコード部分を除いたエラーメッセージを取得します。
	 * メッセージの書式は以下の通りです。
	 * [エラーコード]:エラーメッセージ[備考]
	 * @param message 標準出力
	 * @return エラーメッセージ
	 */
	private static String getErrorMessage(String message) throws NumberFormatException {
		// エラーコードが取得できなかった場合は、空文字を返す
		String errorMessage = "";

		// エラーメッセージ全体を取得する正規表現のうち、
		// エラーコード部分を除いたメッセージを正規表現グループ1とする
		Pattern pattern = Pattern.compile("\\[\\d*\\]:(.*)");
		Matcher matcher = pattern.matcher(message);

		if (matcher.find() && matcher.groupCount() >= 1) {
			// 正規表現グループ1(エラーメッセージ部分)を取得
			errorMessage = matcher.group(1);
		}

		return errorMessage;
	}

  /**
   * PDF事前チェックを実行します。
   * @param args 実行引数
   * 第一引数にはチェックを行うPDFファイルパス(必須)、
   * 第二引数にはパスワード(保護されていない場合は不要)を指定します。
   * 第三引数以降は無視されます。
   * @throws Exception
   */
	public static void main (String[] args) throws Exception{

		CheckResults checkResults = new CheckResults();

		// 引数チェック
		if (args.length >= 1) {
			// チェックを行うPDF、およびそのパスワード(パスワードで保護されていない場合は不要)を指定する
			checkResults = pdfcheck.execute(args[0], (args.length >= 2) ? args[1] : null);
		} else {
			// 引数が不正な(チェックを行うPDFが指定されていない)場合は固定の数値/メッセージとする
			checkResults.code = STATUSCODE_INVALID_ARGS;
			checkResults.message = "引数が不正です";
		}

		if (checkResults.code == STATUSCODE_SUCCESS) {
			System.out.println("PDFチェックで異常は確認されませんでした");
		} else {
			System.out.println("PDFチェックでエラー[" + checkResults.code + "]が発生しました\r\n" + checkResults.message);
		}

		return;
	}
}

4.3.3. エディット機能(Edit) の文字追記を Linux 環境で使用する際の注意点

Linux 環境で エディット機能(Edit) の文字追記を使用する場合は、MS932( Shift_JIS )の文字コードを設定する必要があります。

// 出力先インスタンス作成
pmudst dst = new pmudst();

// テキストオブジェクト生成
pmuobjtext textobj = dst.createobjtext();

//----------------------------------
// Linux環境では文字コード指定が必須
//----------------------------------
textobj.m_encode = "MS932";

// 文字列を追記
sts = text.setstring("これはサンプルです。");

注意

Linux 環境での文字追記には制限事項があります。次を確認してください。

  • 文字コードの指定はテキストオブジェクト(createobjtextメソッドで生成)に適用してください。
  • m_encode には必ず “MS932” を指定してください。
  • 追記する文字(setstringメソッドで指定)は文字コード MS932( Shift_JIS )で扱えるもののみとしてください。

4.4. 体験版ライセンスにおける注意点

試用版ライセンスでご利用のお客様は、30~60 日間の試用期間が終了するとAPIが自動的に利用できない状態となります。

この状態でAPIを利用したプログラムを実行した場合に、実行時エラーとなります。

その場合は、正規の製品ライセンスを購入いただき、アンインストール後に再インストールしてください。

アンインストール・再インストールの方法は、インストールマニュアルをご確認ください。