AWS Lambdaでシーオーリポーツを使う

製品開発担当の大です。こんにちは。

今日は「Amazon S3にシーオーリポーツドキュメントがアップロードされたらPDF化して保存する」という例をご紹介します。

AWS Lambda

もうお気づきの方もいらっしゃると思いますが、これはAWS Lambdaのよくあるユースケースとして紹介されている「写真がアップロードされたらサムネイルを自動的に作成する」という例とほとんど同じです(笑)AWS Lambdaにはさまざまなトリガーが用意されており、S3の監視も設定するだけで行えます。とても楽ちんです。

S3をトリガーに設定

S3をトリガーに設定

今回はPDFを保存する先もS3にする(ただしシーオーリポーツドキュメントをアップロードするバケットとは別のバケットにする)ので、ロールを作成してLambda関数からS3に書き込みができるように設定しておきます。単純なサンプルのため、すでに用意されているポリシーの中からAmazonS3FullAccessとAWSLambdaBasicExecutionRoleを選びました。

ロールの作成

ロールの作成

ソースコード

Lambdaに登録する関数の本体はこのようになっています。シンプルですね。尚、依存関係として、aws-lambda-java-core、aws-lambda-java-events、aws-java-sdk-s3とシーオーリポーツを使用しています。

public class Handler implements RequestHandler<S3Event, String> {
    private static final String DST_BUCKET = "****-pdf";

    @Override
    public String handleRequest(S3Event event, Context context) {
        // イベント発生元のバケットとキーからシーオーリポーツドキュメントを取得します
        var record = event.getRecords().get(0);
        var srcBucket = record.getS3().getBucket().getName();
        var srcKey = record.getS3().getObject().getUrlDecodedKey();

        var s3Client = AmazonS3ClientBuilder.defaultClient();
        var s3Object = s3Client.getObject(new GetObjectRequest(srcBucket, srcKey));
        var os = new ByteArrayOutputStream();
        try (var is = s3Object.getObjectContent()) {
            // シーオーリポーツドキュメントを元にPDFデータを作成します
            createPdf(is, os);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        var pdfData = os.toByteArray();

        // PDFデータを保存用のS3バケットに書き出します
        if (pdfData.length > 0) {
            var meta = new ObjectMetadata();
            meta.setContentLength(pdfData.length);
            meta.setContentType("application/pdf");
            var is = new ByteArrayInputStream(pdfData);
            s3Client.putObject(DST_BUCKET, srcKey.replace(".rsi", ".pdf"), is, meta);
        }
        return "OK";
    }

    private void createPdf(InputStream is, OutputStream os) {
        var job = new CrStreamOutJob(CorDocumentType.PDF, os);
        var draw = new CrDraw();
        try (var bin = CrBinaryDocument.open(draw, is)) {
            job.start(draw);
            bin.printPages();
            job.end();

        } catch (CrException ex) {
            job.abort();
            throw ex;
        } finally {
            draw.deleteInstance();
        }
    }
}

これをAWS Lambdaのハンドラとして登録します。さきほど作成したロールもここで登録します。

ハンドラの登録

ハンドラの登録

パッケージング

今回はmaven shade pluginを使用してパッケージングし、Lambdaに登録しました。
シーオーリポーツのjarはmaven外なので、systemスコープにしてshadeに含めてもらうようにします。

<build>
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
        </resource>
        <resource>
            <directory>${project.basedir}</directory>
            <includes>
                <include>lib/*.jar</include>
            </includes>
        </resource>
    </resources>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.2</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>jp.co.hos</groupId>
        <artifactId>coreports</artifactId>
        <scope>system</scope>
        <version>3.1.1</version>
        <systemPath>${project.basedir}/lib/coreports.jar</systemPath>
    </dependency>
    以下略
</dependencies>

パッケージされたjarをAWS Lambdaの「関数コード」としてアップロードします。

実行

S3バケットにシーオーリポーツドキュメントを追加すると……

シーオーリポーツドキュメントをアップロード

シーオーリポーツドキュメントをアップロード

別のバケットにPDFが作成されましたね!

PDFが作成された

PDFが作成された

ところで

AWSでのシーオーリポーツ for Java V3の使用は現在動作検証中です。検証が終わるまで今しばらくお待ちください……(終わったらここの表示が変わると思います……)