20200707のJavaに関する記事は5件です。

CICS-Javaアプリケーションを動かす - (4)Spring Bootアプリ

はじめに

CICS TS for z/OSでは、Libertyの稼働がサポートされているので、CICS上でJavaEEアプリケーションを動かすことができます。
CICS TS V5.3からSpring Bootをサポートするようになったため、Spring BootのアプリケーションもCICS上で(CICS上のLibertyで)稼働できるようになりました。CICS上で動くということは、CICSの機能を使用するJCICSが使えるということなので、既存のCICSプログラムを呼び出すWebアプリ、CICS管理のVSAMやTSQをアクセスするWebアプリ、といったものがCICSだけで動く、さらにそれをSpring Bootフレームワークを使って開発できる、ということになります。

この記事では、以下GitHubに提供されているCICS-SpringBootアプリのサンプルを動かしてみます。
cics-java-liberty-springboot-jcics

ビルドの管理にはMaven or Gradleどちらも利用できるようになってますが、ここではGradleを使ってみます。

関連記事

CICS-Javaアプリケーションを動かす - (1)単純なサンプルアプリの稼働
CICS-Javaアプリケーションを動かす - (2)Mavenによるビルド管理
CICS-Javaアプリケーションを動かす - (3)Gradleによるビルド管理
CICS-Javaアプリケーションを動かす - (4)Spring Bootアプリ

事前準備

※Gradleでデプロイへの管理まで行う場合、デプロイ先のCICSはCICSplex管理下にある必要があります。

開発環境(PC)

適当なJavaEE開発環境

EclipseやVS CodeなどJavaEEアプリケーション開発ができるものを適宜使用してください。
今回はサンプルをそのまま使うので特にソースの編集はしないので使わなくてもよいですが、通常はなんらかの開発環境使うことになるでしょう。Gradle, gitなどと連携できるとよいかも。
CICS Explorerを一緒に使うのであればEclipse使っておけばOK。

CICS Explorer

こちらも必須ではありませんが、CICSの資源定義とか確認するのに使えます。
以下の辺りを参考にCICS ExplorerというEclipseベースのツールをダウンロードしてセットアップしておきます。
参考: Downloading and starting CICS Explorer
※このツールはCICS利用者は無償で使えるツールです。

Gradle

以下の手順に従ってインストールします。
Installing Gradle
基本的には、ダウンロードしたものを解凍してパスを通すだけ。

前提としてJava8以降が必要になります。

c:\>java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

以下から現時点での最新版Gradle V6.5をダウンロードします(gradle-6.5.zip)。
Releases

適当なディレクトリに展開します。(ここでは(c:\x\Gradle\gradle-6.5)
展開先のbin(C:\x\Gradle\gradle-6.5\bin)をPATHに追加します。

確認

c:\>gradle -v

------------------------------------------------------------
Gradle 6.5
------------------------------------------------------------

Build time:   2020-06-02 20:46:21 UTC
Revision:     a27f41e4ae5e8a41ab9b19f8dd6d86d7b384dad4

Kotlin:       1.3.72
Groovy:       2.5.11
Ant:          Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM:          1.8.0_144 (Oracle Corporation 25.144-b01)
OS:           Windows 10 10.0 amd64

これでOKです。

git

gitHubに提供されるサンプルを入手して使用するので、gitもインストールしておきます。
セットアップ方法などはその辺に転がってるので割愛。

c:\>git --version
git version 2.21.0.windows.1

実行環境(z/OS, CICS)

サンプルを稼働させるCICSリージョンを用意します。
ここでは、CICSplex管理下のCT56B4A1という名前のリージョンを使うことにします。
そこに、Javaアプリケーションを稼働させるためのJVMServerという資源を追加します。
今回は、CICS-Liberty用のサンプル(JavaEEアプリケーション)を使用するので、Liberty用のJVMServerを作成しておきます。

JVMプロファイル

USS上にJVMプロファイルを準備します。(JVMServerに関するプロパティーは実質このUSS上のファイルに指定します。JVMSERVER資源定義ではこのJVMプロファイルのファイル名をポイントすることになります。)
サンプルが提供されているのでそれをコピーして使用します。

/var/cicsts/cicsts56/CT56B4A1/JVMProfiles というディレクトリを作成し、そこに/usr/lpp/cicsts/cicsts56/JVMProfiles/DFHOSGI.jvmprofile(CICS導入ディレクトリ下に配置されているOSGi用のサンプル定義)をコピーします。
環境に合わせて適宜カスタマイズします。

DFHWLP.jvmprofile抜粋
JAVA_HOME=/usr/lpp/java/J8.0_64/
WORK_DIR=/var/cicsts/cicsts56/CT56B4A1/work
WLP_INSTALL_DIR=/usr/lpp/cicsts/cicsts56/wlp
-Dcom.ibm.cics.jvmserver.wlp.autoconfigure=true
-Dcom.ibm.cics.jvmserver.wlp.server.host=*
-Dcom.ibm.cics.jvmserver.wlp.server.http.port=56441
-Dcom.ibm.cics.jvmserver.wlp.server.https.port=56451
-Xms128M
-Xmx256M
-Xmso1M
-Xgcpolicy:gencon
-Xscmx256M
-Xshareclasses:name=cicsts%g,groupAccess,nonfatal
-Xtune:virtualized
-Dcom.ibm.tools.attach.enable=no
-Dfile.encoding=ISO-8859-1
_BPXK_DISABLE_SHLIB=YES

SIT

上のプロパティーファイルを配置したディレクトリを、SITパラメーター"JVMPROFILEDIR"に指定します。

JVMPROFILEDIR=/var/cicsts/cicsts56/CT56B4A1/JVMProfiles 

変更反映のためにリージョンを再起動します。

JVMServer定義

JVMSERVER資源定義を準備します。
製品提供のDFH$WLPというグループにあるJVMSERVER定義"DFHWLP"を適当なグループにコピーしてインストールします。

OBJECT CHARACTERISTICS                                    CICS RELEASE = 0730
 CEDA  View JVmserver( DFHWLP   )                                            
  JVmserver      : DFHWLP                                                    
  Group          : TAGGRP                                                    
  DEScription    : CICS JVM server to run WLP samples                        
  Status         : Enabled            Enabled | Disabled                     
  Jvmprofile     : DFHWLP                                         (Mixed Case
  Lerunopts      : DFHAXRO                                                   
  Threadlimit    : 015                1-256                                  
 DEFINITION SIGNATURE                                                        
  DEFinetime     : 06/04/20 16:20:21                                         
  CHANGETime     : 06/04/20 16:20:21                                         
  CHANGEUsrid    : CICSUSER                                                  
  CHANGEAGEnt    : CSDApi             CSDApi | CSDBatch                      
  CHANGEAGRel    : 0730                                                                     

※Jvmprofile: DFHWLPとなっていますが、これはSITのJVMPROFILEDIRに指定されたディレクトリ下のDFHWLP.jvmprofileというファイルがJVMプロパティーファイルとして使用されることを意味します。

CEMT I JVMSERVERで見てEnableになっていればOK。

I JVMS                                             
STATUS:  RESULTS - OVERTYPE TO MODIFY              
 Jvm(DFHWLP  ) Ena     Prf(DFHWLP  ) Ler(DFHAXRO ) 
    Threadc(005) Threadl( 015 ) Cur(48314096)           

server.xml変更

今回のサンプル実行手順では、Deployまでを自動でやるのではなく手動でデプロイするような手順になっているので、そのための設定を追加しておきます。

JVMプロファイルで-Dcom.ibm.cics.jvmserver.wlp.autoconfigure=trueを指定すると、Libertyの構成が自動で行われます。一度JVMSERVER定義をインストールすると、workディレクトリ下にLibertyが構成されます(work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer)。
このディレクトリ下のserver.xmlを修正して以下のようにします。

server.xml
...
<applicationMonitor dropins="dropins" dropinsEnabled="true" pollingRate="5s" updateTrigger="polled"/>
...

このように、dropinsEnabled="true", updateTrigger="polled"を指定します。
これで、dropinsディレクトリに配置されたwarを自動で検知してくれます。
同ディレクトリにdropinsディレクトリを作成しておきます(.../work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/dropins)。

変更したらJVMServerを再起動しておきます。

CICS Bundle Deployment API

CICS TS V5.6から提供されるようになったCICS Bundle Deployment APIのセットアップをしておく必要があります。(サンプル手順の手動デプロイの場合は不要)
この機能は、CMCIと呼ばれるRESTベースの管理APIの一つとしてアプリケーションのデプロイ用に追加されました。
ターゲットのCICSリージョンを管理するWUIサーバー上にCMCIをセットアップし、CMCI JVMサーバーのプロパティーで、CICS Bundle Deployment API用のパラメーターを指定します。
参考: How it works: CICS bundle deployment API

最低限必要な設定は以下の通りです。
USS上にBundleファイル配置用のディレクトリを作成します。ここでは/var/cicsts/cicsts56/bundlesとします。
WUIのCMCI JVM Server用のJVMプロファイル(EYUCMCIJ.jvmprofile)に、以下のパラメーターを設定します。
-Dcom.ibm.cics.jvmserver.cmci.bundles.dir=/var/cicsts/cicsts56/bundles

サンプルの稼働確認(1) / 手動デプロイ

まずはgithubに提供されている手順に従って動かしてみます。
参考: cics-java-liberty-springboot-jcics

ローカルにクローン作製

適当なディレクトリを作成しローカルのPCにhttps://github.com/cicsdev/cics-java-liberty-springboot-jcics.gitのクローンを作成します。

c:\y\workspace\cicsts56>git clone https://github.com/cicsdev/cics-java-liberty-springboot-jcics.git
Cloning into 'cics-java-liberty-springboot-jcics'...
remote: Enumerating objects: 67, done.
remote: Counting objects: 100% (67/67), done.
remote: Compressing objects: 100% (43/43), done.
remote: Total 67 (delta 12), reused 56 (delta 7), pack-reused 0
Unpacking objects: 100% (67/67), done.

ファイル構造の理解

ディレクトリ"cics-java-liberty-springboot-jcics"に移動して、ファイルの構造を見てみます。

c:\y\workspace\cicsts56\cics-java-liberty-springboot-jcics>tree /f /a
フォルダー パスの一覧:  ボリューム Windows
ボリューム シリアル番号は 1866-E2FC です
C:.
|   .classpath
|   .gitignore
|   .project
|   build.gradle
|   gradlew
|   gradlew.bat
|   LICENSE
|   mvnw
|   mvnw.cmd
|   pom.xml
|   README.md
|   settings.gradle
|
+---.mvn
|   \---wrapper
|           maven-wrapper.jar
|           maven-wrapper.properties
|           MavenWrapperDownloader.java
|
+---.settings
|       org.eclipse.buildship.core.prefs
|       org.eclipse.wst.common.component
|       org.eclipse.wst.common.project.facet.core.xml
|
+---gradle
|   \---wrapper
|           gradle-wrapper.jar
|           gradle-wrapper.properties
|
\---src
    \---main
        +---java
        |   \---com
        |       \---ibm
        |           \---cicsdev
        |               \---springboot
        |                   \---jcics
        |                           Application.java
        |                           BrowseTSQController.java
        |                           DeleteTSQController.java
        |                           ServletInitializer.java
        |                           TSQInfoController.java
        |                           WriteTSQController.java
        |
        \---webapp
            \---WEB-INF
                    ibm-web-ext.xml
                    web.xml

アプリ部分の単発プロジェクトです。
CICS Bundleプロジェクトは含まれていません。
Maven, Gradle両方に対応しているようですが、ここではGradleを使います。

中身の確認/編集

いくつかソースがありますが、例えばWriteTSQController.javaを見てみます。これは見るだけ。

WriteTSQController.java
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* SAMPLE                                                                 */
/*                                                                        */
/* (c) Copyright IBM Corp. 2020 All Rights Reserved                       */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or disclosure */
/* restricted by GSA ADP Schedule Contract with IBM Corp                  */
/*                                                                        */

package com.ibm.cicsdev.springboot.jcics;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.ibm.cics.server.CicsConditionException;
import com.ibm.cics.server.TSQ;

@RestController
public class WriteTSQController {

    /**
     * The @GetMapping annotation ensures that HTTP GET requests are mapped to the annotated method. 
     * @throws IOException 
     **/
    @GetMapping("/writeTSQs")
    public String writeTSQs(@RequestParam(value = "tsqName", defaultValue = "ANNE") String tsqName,
            @RequestParam(value = "tsqContent", defaultValue = "Spring greetings from CICS!") String tsqContent) {

        String response = "";

        // Write to the TSQ
        try {
            response = writeTSQ(tsqName, tsqContent);
        } catch ( CicsConditionException | UnsupportedEncodingException e) {

            // Print the stack trace
            e.printStackTrace();

            // Return useful information to the user when meeting errors
            return "Oops! Unexpected CICS condition exception: "  + e.getMessage() + ". Please check stderr for details.";
        }
        return response;
    }

    /**
     * A method to write a record to a TSQ
     * 
     * @param tsqName, the name of the TSQ to be written to
     * @param record, the data to be written to the TSQ
     * @return, the result of the write 
     * @throws UnsupportedEncodingException 
     * @throws CicsConditionException      
     */
    private String writeTSQ(String tsqName, String record) throws CicsConditionException, UnsupportedEncodingException{

        // Construct the TSQ object
        TSQ tsqQ = new TSQ();
        tsqQ.setName(tsqName);

        // the result of writing an item to the TSQ
        String result = "";

        // write the record to the TSQ
        tsqQ.writeString(record);       
        result = "Record written to TSQ " + tsqName + ".";

        // return the result to the calling servlet
        return result;
    }
}

JCICSのTSQクラスを使ってTSQにデータを書き込むだけの単純なアプリです。URI /writeTSQsのquery parameterでtsqName, tsqContentを受け取り、tsqNameで指定されたTSQにtsqContentで指定された値を書き込むようになっています。

ibm-web-ext.xmlで、context-rootを確認しておきます。これも確認のみ。

ibm-web-ext.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-ext
    xmlns="http://websphere.ibm.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-ext_1_0.xsd"
    version="1.0">

    <reload-interval value="3"/>
    <context-root uri="cics-java-liberty-springboot-jcics-ding" />
    <enable-directory-browsing value="false"/>
    <enable-file-serving value="true"/>
    <enable-reloading value="true"/>
    <enable-serving-servlets-by-class-name value="false" />

</web-ext>

build.gradleを開いて、依存関係の指定をターゲットのCICSのバージョンに合わせて編集します。ここではCICS TS V5.6をターゲットとするので、以下のように修正します。

build.gradle
...
compileOnly enforcedPlatform("com.ibm.cics:com.ibm.cics.ts.bom:5.6-20200609123739")
...

指定する値は以下から判断することになります。
参考:IBM CICS TS BOM

ビルド

以下のコマンドでビルドします。

c:\y\workspace\cicsts56\cics-java-liberty-springboot-jcics>gradlew.bat clean bootwar
Downloading https://services.gradle.org/distributions/gradle-6.5-bin.zip
.........10%..........20%..........30%..........40%.........50%..........60%..........70%..........80%.........90%..........100%
Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 1m 35s
3 actionable tasks: 2 executed, 1 up-to-date

成功すると、以下のWARが作成されます。
build/libs/cics-java-liberty-springboot-jcics-0.1.0.war

デプロイ

このサンプルの手順では手動でWARをデプロイするようになっているので、一旦それでやってみます。

先に作成しておいた、dropinsディレクトリにバイナリモードで上のWARファイルを転送します。
これで自動でアプリが認識されるはずです。
(この方式の場合、BUNDLE定義は使いません)

アプリ稼働確認

ブラウザから、ターゲットのLibertyがListenしているhost:portに対して以下のようなリクエストを投げてみます。
http://etp1:56441/cics-java-liberty-springboot-jcics-ding/writeTSQs?tsqName=SPGJCICS&tsqContent=ILOVECICS
SPGJCICSという名前のTSQにILOVECICSというメッセージを投入することになります。
うまくいけば、TSQにデータが書き込まれるので、CICS端末からCEBRで確認してみます。
image.png
きちんとデータが投入されていることが確認できました。

サンプルの稼働確認(2) / Gradleによるデプロイ

さて、上の手順だとデプロイが手動になってしまいスマートでは無いので、DeployまでGradleで実施できるようCICS Bundleプロジェクトを追加してみます。

注意!: 上の手順で手動デプロイを試した場合は、アプリがバッティングするのでdropinsディレクトリのwarを削除し、JVMSERVERを再起動しておいてください。

Gradleマルチプロジェクト作成

CICS Bundleプロジェクトを追加し、サンプルで提供されているWARとまとめるための親のプロジェクトを作成します。

親プロジェクト

まず、親となるプロジェクトのディレクトリ cics-springboot01というディレクトリを作成します。そこでgradle wrapperを実行しておきます。

c:\y\workspace\cicsts56\cics-springboot01>gradle wrapper

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 6s
1 actionable task: 1 executed
c:\y\workspace\cicsts56\cics-springboot01>tree /a /f
フォルダー パスの一覧:  ボリューム Windows
ボリューム シリアル番号は 1866-E2FC です
C:.
|   gradlew
|   gradlew.bat
|
+---.gradle
|   +---6.5
|   |   |   gc.properties
|   |   |
|   |   +---executionHistory
|   |   |       executionHistory.bin
|   |   |       executionHistory.lock
|   |   |
|   |   +---fileChanges
|   |   |       last-build.bin
|   |   |
|   |   +---fileHashes
|   |   |       fileHashes.bin
|   |   |       fileHashes.lock
|   |   |
|   |   \---vcsMetadata-1
|   +---buildOutputCleanup
|   |       buildOutputCleanup.lock
|   |       cache.properties
|   |       outputFiles.bin
|   |
|   +---checksums
|   |       checksums.lock
|   |
|   \---vcs-1
|           gc.properties
|
\---gradle
    \---wrapper
            gradle-wrapper.jar
            gradle-wrapper.properties

ここに、以下のようにbuild.gradle, setting.gradleを作成します。

build.gradle
group 'com.ibm.cicsdev.springboot'
version '1.0.0'
setting.gradle
rootProject.name = 'cics-springboot01'
include 'cics-java-liberty-springboot-jcics'
include 'cics-springboot-bundle04'

子プロジェクト(1) / WAR用

これは、サンプルで提供されているものをそのまま使います。
上で示した手順通り、親プロジェクトのディレクトリ下でgit cloneでcics-java-liberty-springboot-jcicsをクローンします。
その後、ターゲットのCICSのバージョンに合わせて、build.gradleのcompileOnlyの行を修正します。

子プロジェクト(2) / CICS Bundle用

これは前回の記事を参考に、バンドル用のbuild.gradleを作成してきます。
参考: CICS-Javaアプリケーションを動かす - (3)Gradleによるビルド管理

親プロジェクトのディレクトリ下に、cics-springboot-bundle04という名前のディレクトリを作成し、そこに以下のようなbuild.gradleを作成します。ディレクトリ名は親のsetting.gradleで指定した名前に合わせます。

build.gradle
plugins {
    id 'com.ibm.cics.bundle' version '1.0.0'
}

group 'com.ibm.cicsdev.springboot'
version '1.0.0'

repositories {
    mavenCentral()
}

cicsBundle {
    build {
        defaultJVMServer = 'DFHWLP' // (1)JVMSERVER名
    }
    deploy {
        cicsplex = 'C73PLX'         // (2) ターゲットのCICSリージョンが属しているCICSplex名
        region   = 'CT56B4A1'       // (3) ターゲットのCICSリージョン名
        bunddef  = 'SPBBUNDL'       // (4) ターゲットのCICSリージョン上に定義したバンドル定義資源名
        csdgroup = 'TAGGRP'         // (5) (4)のバンドル定義が属しているCSDグループ名
        url      = 'http://etp1:56002'     // (6) WUIのCMCIのURL
        username = 'TAG'           // (7) CMCIによるDeployment API発行時に使用するユーザーと
        password = 'xxxxxxxx'      //   パスワード
        //caution: uncomment the line below to disable TLS/SSL checking for certificates
        //insecure = true
    }
}

dependencies {
    cicsBundlePart project(path:':cics-java-liberty-springboot-jcics', configuration: 'archives')
}

最終的にはこんな感じの構造になります。

c:\y\workspace\cicsts56\cics-springboot01>tree /a /f
フォルダー パスの一覧:  ボリューム Windows
ボリューム シリアル番号は 1866-E2FC です
C:.
|   build.gradle
|   gradlew
|   gradlew.bat
|   settings.gradle
|

...

+---cics-java-liberty-springboot-jcics
|   |   .classpath
|   |   .gitignore
|   |   .project
|   |   build.gradle
|   |   build_original.gradle
|   |   gradlew
|   |   gradlew.bat
|   |   LICENSE
|   |   mvnw
|   |   mvnw.cmd
|   |   pom.xml
|   |   README.md
|   |   settings.gradle
|   |
|   +---.gradle
|   |   +---6.5
|   |   |   |   gc.properties
|   |   |   |
|   |   |   +---executionHistory
|   |   |   |       executionHistory.bin
|   |   |   |       executionHistory.lock
|   |   |   |
|   |   |   +---fileChanges
|   |   |   |       last-build.bin
|   |   |   |
|   |   |   +---fileContent
|   |   |   |       fileContent.lock
|   |   |   |
|   |   |   +---fileHashes
|   |   |   |       fileHashes.bin
|   |   |   |       fileHashes.lock
|   |   |   |
|   |   |   +---javaCompile
|   |   |   |       classAnalysis.bin
|   |   |   |       javaCompile.lock
|   |   |   |       taskHistory.bin
|   |   |   |
|   |   |   \---vcsMetadata-1
|   |   +---buildOutputCleanup
|   |   |       buildOutputCleanup.lock
|   |   |       cache.properties
|   |   |       outputFiles.bin
|   |   |
|   |   +---checksums
|   |   |       checksums.lock
|   |   |       md5-checksums.bin
|   |   |       sha1-checksums.bin
|   |   |
|   |   \---vcs-1
|   |           gc.properties
|   |
|   +---.mvn
|   |   \---wrapper
|   |           maven-wrapper.jar
|   |           maven-wrapper.properties
|   |           MavenWrapperDownloader.java
|   |
|   +---.settings
|   |       org.eclipse.buildship.core.prefs
|   |       org.eclipse.wst.common.component
|   |       org.eclipse.wst.common.project.facet.core.xml
|   |
|   +---gradle
|   |   \---wrapper
|   |           gradle-wrapper.jar
|   |           gradle-wrapper.properties
|   |
|   \---src
|       \---main
|           +---java
|           |   \---com
|           |       \---ibm
|           |           \---cicsdev
|           |               \---springboot
|           |                   \---jcics
|           |                           Application.java
|           |                           BrowseTSQController.java
|           |                           DeleteTSQController.java
|           |                           ServletInitializer.java
|           |                           TSQInfoController.java
|           |                           WriteTSQController.java
|           |
|           \---webapp
|               \---WEB-INF
|                       ibm-web-ext.xml
|                       web.xml
|
+---cics-springboot-bundle04
|       build.gradle
|
\---gradle
    \---wrapper
            gradle-wrapper.jar
            gradle-wrapper.properties

BUNDLE定義作成

上のbuild.gradleで指定した内容に従って、バンドル定義を作成します。

OBJECT CHARACTERISTICS                                    CICS RELEASE = 0730 
 CEDA  View Bundle( SPBBUNDL )                                                
  Bundle         : SPBBUNDL                                                   
  Group          : TAGGRP                                                     
  DEScription    : CICS-SpringBoot-Sample                                     
  Status         : Enabled            Enabled | Disabled                      
  BUndledir      : /var/cicsts/cicsts56/bundles/cics-springboot-bundle04_1.0. 
  (Mixed Case)   : 0                                                          
                 :                                                            
                 :                                                            
                 :                                                            
  BAsescope      :                                                            
  (Mixed Case)   :                                                            
                 :                                                            
                 :                                                            
                 :                                                            
 DEFINITION SIGNATURE                                                         
  DEFinetime     : 07/07/20 17:03:45                                          
  CHANGETime     : 07/07/20 17:03:57                                          

                                                    SYSID=B4A1 APPLID=CT56B4A1
                              DSN=CICSTS56.CICS.DFHCSD                        

CSDグループは(5)、BUNDLE定義名は(4)、BUNDLEDIRはプロジェクトのディレクトリ名およびバージョン情報の値を元に指定します。
※ここでは、まだインストール操作はしません

ビルド/デプロイ実行

以下のようにSpring BootのWARをビルドします。

c:\y\workspace\cicsts56\cics-springboot01>gradlew bootWar

BUILD SUCCESSFUL in 6s
2 actionable tasks: 2 executed

続いて、CICS Bundleのビルドとデプロイを実行します。

c:\y\workspace\cicsts56\cics-springboot01>gradlew deployCICSBundle

> Task :cics-springboot-bundle04:buildCICSBundle
Adding Java-based bundle parts from 'cicsBundlePart' dependency configuration
Adding Java-based bundle part: 'C:\y\workspace\cicsts56\cics-springboot01\cics-java-liberty-springboot-jcics\build\libs\cics-java-liberty-springboot-jcics-0.1.0.war'
Adding non-Java-based bundle parts from 'src/main/resources'

> Task :cics-springboot-bundle04:deployCICSBundle
Task deployCICSBundle

BUILD SUCCESSFUL in 29s
4 actionable tasks: 3 executed, 1 up-to-date

CICS Explorerからバンドル、バンドルパーツがENABLEDになっているのが確認できればOKです。
image.png

デプロイまでGradleでできました!

ちなみに、Libertyのmessages.logをみると、SpringBootのアプリが稼働したのが分かります。

[7/7/20 9:20:35:354 GMT] 000000d0 LogService-87-com.ibm.cics.wlp.bundlepart.impl               I CWWKE0703I: [com.ibm.cics.wlp.bundlepart.impl] [CICSLibertyBundlepartControllerImpl] @Info : installBundlepart() - cics-java
-liberty-springboot-jcics-0.1.0, SPBBUNDL, 2, /var/cicsts/cicsts56/bundles/cics-springboot-bundle04_1.0.0/, 1.0.0, 206F2740000001E9, , , -1, -1, -1, CSD_API
[7/7/20 9:20:35:376 GMT] 000000d1 LogService-87-com.ibm.cics.wlp.bundlepart.impl               I CWWKE0703I: [com.ibm.cics.wlp.bundlepart.impl] [CICSLibertyBundlepartControllerImpl] @Info : enableBundlepart() - 3549516473

[7/7/20 9:20:36:381 GMT] 00000055 com.ibm.ws.app.manager.AppMessageHelper                      I CWWKZ0018I: Starting application cics-java-liberty-springboot-jcics-0.1.0.
[7/7/20 9:20:36:382 GMT] 00000055 bm.ws.app.manager.war.internal.WARDeployedAppInfoFactoryImpl I CWWKZ0136I: The cics-java-liberty-springboot-jcics-0.1.0 application is using the archive file at the /var/cicsts/cicsts56/C
T56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/installedApps/cics-java-liberty-springboot-jcics-0.1.0.war location.
[7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.webcontainer.osgi.webapp.WebGroup                 I SRVE0169I: Loading Web Module: cics-java-liberty-springboot-jcics.
[7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.webcontainer                                      I SRVE0250I: Web Module cics-java-liberty-springboot-jcics has been bound to default_host.
[7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.http.internal.VirtualHostImpl                     A CWWKT0016I: Web application available (default_host): http://etp1:56441/cics-java-liberty-springboot-jcics-ding/
[7/7/20 9:20:36:725 GMT] 00000055 com.ibm.ws.app.manager.AppMessageHelper                      A CWWKZ0003I: The application cics-java-liberty-springboot-jcics-0.1.0 updated in 0.344 seconds.
[7/7/20 9:20:36:733 GMT] 0000004d com.ibm.ws.webcontainer.osgi.mbeans.PluginGenerator          I SRVE9103I: A configuration file for a web server plugin was automatically generated for this server at /var/cicsts/cicsts56/
CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/logs/state/plugin-cfg.xml.
[7/7/20 9:20:36:800 GMT] 0000004b com.ibm.ws.session.WASSessionCore                            I SESN0176I: A new session context will be created for application key default_host/cics-java-liberty-springboot-jcics-ding
[7/7/20 9:20:36:801 GMT] 0000004b com.ibm.ws.util                                              I SESN0172I: The session manager is using the Java default SecureRandom implementation for session ID generation.
[7/7/20 9:20:37:064 GMT] 0000004b com.ibm.ws.webcontainer.webapp                               I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.2 Spring WebApplicationInitializers detected on cla
sspath
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O   .   ____          _            __ _ _
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O   '  |____| .__|_| |_|_| |_\__, | / / / /
[7/7/20 9:20:37:973 GMT] 0000004b SystemOut                                                    O  =========|_|==============|___/=/_/_/_/
[7/7/20 9:20:37:974 GMT] 0000004b SystemOut                                                    O  :: Spring Boot ::        (v2.3.0.RELEASE)
[7/7/20 9:20:38:131 GMT] 0000004b SystemOut                                                    O 2020-07-07 09:20:38.128  INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer         : Starting ServletInit
ializer on etp1.tsc.ibm.com with PID 83952403 (/var/cicsts/cicsts56/CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/installedApps/cics-java-liberty-springboot-jcics-0.1.0.war started by STCUSR in /ETP1/var/cic
sts/cicsts56/CT56B4A1/work)
[7/7/20 9:20:38:133 GMT] 0000004b SystemOut                                                    O 2020-07-07 09:20:38.133  INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer         : No active profile se
t, falling back to default profiles: default
[7/7/20 9:20:38:446 GMT] 00000053 com.ibm.ws.config.xml.internal.ConfigRefresher               A CWWKG0016I: Starting server configuration update.
[7/7/20 9:20:38:448 GMT] 00000053 com.ibm.ws.config.xml.internal.XMLConfigParser               A CWWKG0028A: Processing included configuration resource: /var/cicsts/cicsts56/CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/d
efaultServer/installedApps.xml
[7/7/20 9:20:38:450 GMT] 00000053 com.ibm.ws.config.xml.internal.ConfigRefresher               A CWWKG0018I: The server configuration was not updated. No functional changes were detected.
[7/7/20 9:20:39:214 GMT] 0000004b com.ibm.ws.webcontainer.webapp                               I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.Initializing Spring embedded WebApplicationContext
[7/7/20 9:20:39:214 GMT] 0000004b SystemOut                                                    O 2020-07-07 09:20:39.214  INFO 83952403 --- [RVICE_Thread-28] o.s.web.context.ContextLoader            : Root WebApplicationC
ontext: initialization completed in 1011 ms
[7/7/20 9:20:39:608 GMT] 0000004b SystemOut                                                    O 2020-07-07 09:20:39.608  INFO 83952403 --- [RVICE_Thread-28] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing Executo
rService 'applicationTaskExecutor'
[7/7/20 9:20:39:847 GMT] 0000004b SystemOut                                                    O 2020-07-07 09:20:39.846  INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer         : Started ServletIniti
alizer in 2.638 seconds (JVM running for 3347.897)
[7/7/20 9:25:53:853 GMT] 00000045 com.ibm.ws.webcontainer.webapp                               I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.Initializing Spring DispatcherServlet 'dispatcherSe
rvlet'
[7/7/20 9:25:53:853 GMT] 00000045 SystemOut                                                    O 2020-07-07 09:25:53.853  INFO 83952403 --- [HP.TASK205.CJSA] o.s.web.servlet.DispatcherServlet        : Initializing Servlet
 'dispatcherServlet'
[7/7/20 9:25:53:863 GMT] 00000045 SystemOut                                                    O 2020-07-07 09:25:53.863  INFO 83952403 --- [HP.TASK205.CJSA] o.s.web.servlet.DispatcherServlet        : Completed initializa
tion in 10 ms
[7/7/20 9:25:53:863 GMT] 00000045 com.ibm.ws.webcontainer.servlet                              I SRVE0242I: [cics-java-liberty-springboot-jcics-0.1.0] [/cics-java-liberty-springboot-jcics-ding] [dispatcherServlet]: Initia
lization successful.

アプリ稼働確認

先の例と同様、ブラウザからTSQに書き込むアプリを実行してみます。今度は書き込む文字列を"ILOVECICS2"にしています。
image.png
正常に結果が返りました。
CICS端末からCEBRで確認すると、きちんとデータが書き込まれていることが確認できました!
image.png

サンプルのカスタマイズ

CICS TS V5.5 + APAR PH14856 or V5.6 base では、Spring Bootアプリを従来のCICSプログラムのように扱うことができるようになるため、EXEC CICS LINKでSpring Bootプログラムを呼び出したり、EXEC CICS STARTで呼び出すことができるようになります。
参考: Linking to a Java EE or Spring Boot application from a CICS program

ここでは、COBOLなどの言語からEXEC CICS LINK でSpring Bootアプリを呼び出すシナリオを試してみます。
EXEC CICS LINK でSpring Bootアプリを呼び出す際、データの受け渡しはChannel & Containerを使いますが、今回は簡素化のためデータ受け渡しは行わずに単純にプログラム呼び出しの部分のみ追加実装して試してみます。

server.xml変更

Liberty上のプログラムを呼び出す構成を行う場合、ランタイムとなるLibertyのフィーチャーとしてcicsts:link-1.0を追加する必要があります。以下のようにfeatureを追加してJVMServerを再起動(Disabled=>Enabled)しておきます。

server.xml
...
    <featureManager>
        <feature>cicsts:core-1.0</feature>
        <feature>cicsts:defaultApp-1.0</feature>
        <feature>jsp-2.3</feature>
        <feature>wab-1.0</feature>
        <feature>transportSecurity-1.0</feature>
        <feature>cicsts:link-1.0</feature>
    </featureManager>
...

サンプルプロジェクトをEclipseへ取り込む

上で取り扱ったGitHubで提供されているサンプルプロジェクトをEclipseに取り込みます。ここではCICS Explorerとして提供されているEclipseを使います。

Eclipse Marketplaceから、Buildship Gradle Integrationをインストールしておきます。
image.png
image.png

Javaパースペクティブのパッケージ・エクスプローラー・ビューで、右クリック - インポート - フォルダまたはアーカイブからのプロジェクト で、cloneしたプロジェクトのディレクトリを選択して取り込みます。
image.png

取り込み後は赤×がついてエラー表示になっています。
image.png

プロジェクト右クリック - Gradle - Refresh Gradle Project
image.png

エラーが消えました!
image.png

ロジック追加

まず、build.gradleに依存関係を追加します。dependenciesに以下を追加します。

build.gradle
...
dependencies 
{
   ...
    // for @CICSProgram annotation
    compileOnly ("com.ibm.cics:com.ibm.cics.server.invocation.annotations")
    annotationProcessor ("com.ibm.cics:com.ibm.cics.server.invocation:5.6")
}

Refresh Gradle Projectを実行しておきます。

WriteTSQController.javaと同じパッケージに、以下のファイルを作成します。

WriteTSQLinked.java
package com.ibm.cicsdev.springboot.jcics;

import org.springframework.stereotype.Component;
import com.ibm.cics.server.CicsConditionException;
import com.ibm.cics.server.TSQ;
import com.ibm.cics.server.invocation.CICSProgram;

@Component
public class WriteTSQLinked {

    @CICSProgram("WRTTSQ")
    public void writeTSQlinked()
    {     
        String tsqName = "SPGJCICS";
        String record  = "ILOVECICS3";

        // Write to the TSQ
        try {
            // Construct the TSQ object
            TSQ tsqQ = new TSQ();
            tsqQ.setName(tsqName);

            // write the record to the TSQ
            tsqQ.writeString(record);       

        } catch ( CicsConditionException  e) {
            // Print the stack trace
            e.printStackTrace();
        }
    }
}

@CICSProgramアノテーションで、直後のメソッドを"WRTTSQ"という名前のCICSプログラムとして認識させています。
CICSプログラムとして認識させる場合、メソッドはpublic指定、引数なしで定義する必要があります。
今回は引数なしで、埋め込みでSPGJCICSというTSQにILOVECICS3という値を書き出すロジックを追加しています。

ビルド/デプロイ

C:\y\workspace\cicsts56\cics-springboot02>gradlew bootWar

BUILD SUCCESSFUL in 7s
2 actionable tasks: 2 executed
C:\y\workspace\cicsts56\cics-springboot02>gradlew deployCICSBundle

> Task :cics-springboot-bundle04:buildCICSBundle
Adding Java-based bundle parts from 'cicsBundlePart' dependency configuration
Adding Java-based bundle part: 'C:\y\workspace\cicsts56\cics-springboot02\cics-java-liberty-springboot-jcics\build\libs\cics-java-liberty-springboot-jcics-0.1.0.war'
Adding non-Java-based bundle parts from 'src/main/resources'

> Task :cics-springboot-bundle04:deployCICSBundle
Task deployCICSBundle

BUILD SUCCESSFUL in 1m 31s
4 actionable tasks: 3 executed, 1 up-to-date

完了すると、バンドルがインストールされ、WARがバンドルパーツとしてインストールされます。さらに、そこに含まれる@CICSProgramで指定したメソッドがCICSプログラムとして認識されるため、CICSプログラム"WRTTSQ"がインストールされた状態になります。

image.png

インストールされたプログラム定義の詳細はこんな感じ(CICS Explorerで確認)
image.png

ターゲットのリージョンのJOBLOGにはこんな感じのメッセージが出ています。

DFHRL0107 I 07/08/2020 15:40:30 CT56B4A1 CICSUSER The CICS resource lifecycle manager has started to create the BUNDLE resource    
           SPBBUNDL.                                                                                                               
DFHRL0125 I 07/08/2020 15:40:30 CT56B4A1 CICSUSER BUNDLE resource SPBBUNDL is being created with BUNDLEID cics-springboot-bundle04 
           and version 1.0.0.                                                                                                      
DFHSJ1105 07/08/2020 15:40:30 CT56B4A1 WAR bundle cics-java-liberty-springboot-jcics-0.1.0 version 1.0.0 from BUNDLE SPBBUNDL has  
           been installed as Disabled.                                                                                             
DFHRL0108 I 07/08/2020 15:40:30 CT56B4A1 CONL The CICS resource lifecycle manager is in the process of creating the BUNDLE resource
           SPBBUNDL and the BUNDLE is in the enabling state.                                                                       
DFHRD0128 I 07/08/2020 15:40:30 CT56B4A1  CICSUSER CONL INSTALL BUNDLE(SPBBUNDL)                                                   
???? ??? CONL CICSUSER 07/08/20 15:40:30 INSTALL BUNDLE(SPBBUNDL) GROUP(TAGGRP)                                                    
DFHFC0961 07/08/2020 15:40:30 CT56B4A1 Calculation of LSR pool 1 parameters incomplete. Filename DFHDBFK has no DSNAME.            
DFHPG0101 07/08/2020 15:40:34 CT56B4A1  CICSUSER CJSP Resource definition for WRTTSQ has been added.                               
DFHSJ1204 07/08/2020 15:40:34 CT56B4A1 A linkable service has been registered for program WRTTSQ in JVMSERVER DFHWLP with classname
           com.ibm.cicsdev.springboot.jcics.WriteTSQLinked, method writeTSQlinked.                                                 
DFHSJ1107 07/08/2020 15:40:34 CT56B4A1 WAR bundle with symbolic name cics-java-liberty-springboot-jcics-0.1.0 version 1.0.0 has bee
           Enabled.                                                                                                                
DFHRL0132 I 07/08/2020 15:40:34 CT56B4A1 CJSL All defined resources for BUNDLE SPBBUNDL are now in the enabled state.              
DFHAP1900 07/08/2020 15:40:40 CT56B4A1 NONE CICSUSER CONL SET BUNDLE(SPBBUNDL) ENABLESTATUS(ENABLED) RESP(NORMAL) RESP2(0).        

アプリ稼働確認

簡易的にCICS端末から`CECI LINK PROGRAM(WRTTSQ)'発行してみます。
image.png

CEBRでTSQ"SPGJCICS"の中身を確認してみます。
image.png

期待したメッセージが書き込まれています!
これで、EXEC CICS LINKを使用してSpring Bootアプリを呼び出す流れが確認できました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

例外処理について

例外とは

例外は、プログラム上で想定外の動作が行われ、処理が続行できなくなったことを通知するためのオブジェクトです。
例外を使えば、コードの正常処理と以上処理をある程度分離できるため、コードが読みやすくなります。

エラーと例外の違い

Java実行中のトラブルは,エラーと例外の2種類に分けられます。

エラー
実行環境のトラブル等、プログラムから対処不可能な事態。
プログラムが続行できなくなり、強制終了してしまいます。

例外
プログラムから対処可能な事態。
エラーとは違い、動作を終わらせることなくプログラムを続行できます。

チェック(検査)例外

メソッドを記述する際、例外処理も書かないと怒られるのがチェック例外で、チェック例外は基本的に、正しいプログラムを書いていても避けられない例外です。例えば、参照したいファイルが壊れているとか、DB障害等がこれにあたります。
チェック例外はコンパイラがチェックする例外処理で、Exeptionやそのサブクラス等が対象です。

非チェック(検査)例外

例外処理を記述したかをコンパイラがチェックしない例外です。
非チェック例外はプログラマーが任意で記述するもので、RuntimeExcepitonクラスやそのサブクラス等が対象です。非チェック例外は基本的には避けられるエラーで、必ず記載しなければならないものではありません。

main.java
public static void main (String[] args) {

      int[] ary = {1, 2, 3};

      System.out.println(ary[3]);
}

上記のコードでは、配列aryの要素が3つしか無いのに、4番目を表示するように要求しています。
実行すると以下のようになります。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

配列の範囲外を見ようとしているというメッセージが出ました。

これに例外処理を追加して実行してみます。

main.java
class Main{
    public static void main(String args[]){
        try{
            int[] ary = {1, 2, 3};

            System.out.println(ary[3]);
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("例外です");
        }
    }
}

実行結果

例外です

例外処理が走りました。

try~catch~finaly文

sample.java
class Sample {
    public static void main (String[] args) {
        int ary[] = {1, 2, 3};

        System.out.println("開始");

            try{
                for (int i = 0; i < 4; i++){
                    System.out.println(n[i]);
                }
            }
            catch(ArrayIndexOutOfBoundsException e){
                System.out.println("配列の範囲を超えています");
            }
            finally{
                System.out.println("配列を出力");
            }

            System.out.println("処理を終了");
        }
}

tryの部分に例外が発生する可能性のある処理を記載し、catchの部分に例外が発生したときの処理を書きます。例外の種類によってcatchブロックをそれぞれに分けることもできます。finalyの部分で最後に実行される処理を記載します。

throwとthrows

throw

try~catchでの例外処理以外に、自分で例外を起こせるthrowという例外処理もあります。

sample.java
    void test (int num) { 
        if(num == 0) { 
            throw new IllegalArgumentException("引数が不正です"); 
        }
    }

testメソッドではnumという数値型を引数に指定しているにもかかわらず、if分でnumが0だった時に処理をするように書いています。

実行すると以下のようになります。

throw new IllegalArgumentException(“引数が不正です”);

throws

throwと名前は似ていますが処理内容は異なります。
throwsは、例外処理をメソッド内ではなく呼び出し元で行いたい時に、呼び出し元に呼ぶことができます。

sample.java
import java.io.FileNotFoundException;
import java.io.FileReader;

class Sample {
    public static void main (String[] args) {
        System.out.println("例外スロー");

        try {
            methodA(); 
        } catch(FileNotFoundException e) {
            System.err.println(e.getMessage());
        } 
    }

    void methodA() throws FileNotFoundException {
        FileReader aFile = new FileReader("aFile.txt");
    }
}

実行結果

aFile.txt (No such file or directory)
処理が終わりました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBoot入門ガイドやってみた【Accessing Data with JPA編】

目的

Spring Quickstart Guideを取り組み終えた方、SpringBootを学び始めた方、復習をしたい方に向けて、

公式が人気ガイドだからやってみて!と勧めてくれている、Accessing Data with JPAを実際に取り組み学んだことを共有します。

開発環境
OS: macOS Mojave バージョン10.14.6
テキストエディタ: Visual Studio Code(以下VSCode)
Java: 11.0.2

QuickstartGuideのおさらいはこちらから
Building a RESTful Web Service編のおさらいはこちらから
Consuming a RESTful Web Service編のおさらいはこちらから

1.SpringBoot projectを始めよう!

まずは、spring initializrにアクセスします。

1.ADD DEPENDENCIESボタンをクリックして、Spring Data JPAH2 Databaseを追加。
スクリーンショット 2020-07-06 13.52.15.png
スクリーンショット 2020-07-06 13.52.27.png

Spring Data JPA(Java Persistence API)とは、Javaのオブジェクトをデータベースに保存したり取り出したりするためのAPIです(O/Rマッピングしてくれるもの)。

H2 Databasetohaとは、Javaに標準で用意されているデータベース。ここで追加することによりMySQLなど別途サーバーを立てる必要がないので便利ですね。

2.Artifact, Nameは、accessing-data-jpaに変更。
3.Javaを11に変更。

そしてGENERATEボタンをクリックしてZipファイルをダウンロードします。

スクリーンショット 2020-07-06 13.55.11.png

ダウンロードしたZipファイルを展開したら準備完了です。

2.コードを追加しよう!

先ほどのフォルダをVSCodeで開きます。
拡張機能のJava Extension Packのインストールの推奨します。と言われるのでインストールしておきましょう。(未インスールの方のみ)

スクリーンショット 2020-06-30 10.08.25.png

Customer.javaを作成しよう!

src/main/java/com/example/accessingdatajpa/にCustomer.javaファイルを作成します。

スクリーンショット 2020-07-06 14.11.51.png

Customer.javaファイル内にコードを追加していきます。

Customer.java
package com.example.accessingdatajpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private String firstName;
  private String lastName;

  protected Customer() {}

  public Customer(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return String.format(
        "Customer[id=%d, firstName='%s', lastName='%s']",
        id, firstName, lastName);
  }

  public Long getId() {
    return id;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }
}

Customer.javaファイルに追加したコードを深掘りしていきます。

@Entity

Customer.java
@Entity
public class Customer {
  // 省略
}

@Entityアノテーションは、DBのテーブルと結びつくクラスとなります(エンティティクラス)。
このエンティティクラスで定義された変数は、DBのカラムと結びつきます。

@Id@GeneratedValue(strategy=GenerationType.AUTO)、コンストラクタ

Customer.java
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;

protected Customer() {}

public Customer(String firstName, String lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

@Idアノテーションは、付与されている変数がテーブルの主キーになります。
また、@GeneratedValue(strategy=GenerationType.AUTO)アノテーションで、idが連番で自動的に生成してくれるようになります。

今回のCustomerテーブルは、主キーがid、その他のカラムはfirstNameとlastNameが存在するという事です。

エンティティクラスの要件として、引数のないコンストラクタが必要ですので、引数なしのコンストラクタを定義、
引数があるコンストラクタは、DBに保存するインスタンスを生成する時の為に定義しています。

③toStringメソッド、ゲッターメソッドの定義

Customer.java
@Override
public String toString() {
  return String.format(
     "Customer[id=%d, firstName='%s', lastName='%s']",
      id, firstName, lastName);
}

public Long getId() {
  return id;
}

public String getFirstName() {
  return firstName;
}

public String getLastName() {
  return lastName;
}

toStringメソッドは、java.lang.Objectクラスで定義されている文字列表現を返すメソッドです。
@Overrideアノテーションは、Objectクラスで定義されているtoStringメソッドをこのクラスでオーバーライドしています。と明示するためのアノテーションです。

正しくオーバーライドされていなければエラーになります。
よって、toStrign()のようにタイプミスをしてしまっていると、コンパイル時にエラーが出て教えてくれます。

今回は、idとfirstNameとlastNameを表示するための文字列を返すメソッドにオーバーライドしています。

String.formatというメソッドを使用する際に、第一引数に決められた書式を指定しなければいけないため、
%sは、文字列、%dは10進数整数と書式を指定しています。

後は、それぞれの変数を取得するためのゲッターメソッドを定義しています。

CustomerRepository.javaを作成しよう!

src/main/java/com/example/accessingdatajpa/にCustomerRepository.javaファイルを作成します。

スクリーンショット 2020-07-07 12.01.41.png

CustomerRepository.javaファイル内にコードを追加していきます。

CustomerRepository.java
package com.example.accessingdatajpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

  List<Customer> findByLastName(String lastName);

  Customer findById(long id);

}

CustomerRepository.javaファイルに追加したコードを深掘りしていきます。

①リポジトリインターフェースを作成する

CustomerRepository.java
public interface CustomerRepository extends CrudRepository<Customer, Long> {
  // 省略
}

CustomerRepositoryというインターフェースを作成しています。その時にCrudRepositoryというインターフェースを継承しています。
CrudRepositoryインターフェースは引数にエンティティの型であるCustomer、IDの型であるLongをジェネリックパラメーターとして指定しています。

CrudRepositoryインターフェースは、Create、Read、Update、Delete(CRUD)という操作が出来るインターフェースです。
よって、CustomerRepositoryインターフェースも上記操作が出来るようになります。

②メソッドの実装

CustomerRepository.java
List<Customer> findByLastName(String lastName);

Customer findById(long id);

Spring Data JPAでは、findBy〇〇と特定の命名規則を満たすメソッドはその内容からクエリメソッドとして定義されます。

今回は、findByLastName(String lastName)が該当します。引数で受け取ったlastNameと一致するデータを全て取得する事が可能なメソッドです。
findById(long id)は、特定のidと一致するデータを取得する事が可能なメソッドです。

AccessingDataJpaApplication.javaを編集しよう!

デフォルトの状態は以下のようになっていると思います。

AccessingDataJpaApplication.java
package com.example.accessingdatajpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataJpaApplication {

    public static void main(String[] args) {
      SpringApplication.run(AccessingDataJpaApplication.class, args);
    }

}

公式を参考にしつつコードを追加します。

AccessingDataJpaApplication.java
package com.example.accessingdatajpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 追加したコード
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AccessingDataJpaApplication {

  // 追加したコード
  private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

  public static void main(String[] args) {
    SpringApplication.run(AccessingDataJpaApplication.class);
  }

  // 追加したコード
  @Bean
  public CommandLineRunner demo(CustomerRepository repository) {
    return (args) -> {
      // save a few customers
      repository.save(new Customer("Jack", "Bauer"));
      repository.save(new Customer("Chloe", "O'Brian"));
      repository.save(new Customer("Kim", "Bauer"));
      repository.save(new Customer("David", "Palmer"));
      repository.save(new Customer("Michelle", "Dessler"));

      // fetch all customers
      log.info("Customers found with findAll():");
      log.info("-------------------------------");
      for (Customer customer : repository.findAll()) {
        log.info(customer.toString());
      }
      log.info("");

      // fetch an individual customer by ID
      Customer customer = repository.findById(1L);
      log.info("Customer found with findById(1L):");
      log.info("--------------------------------");
      log.info(customer.toString());
      log.info("");

      // fetch customers by last name
      log.info("Customer found with findByLastName('Bauer'):");
      log.info("--------------------------------------------");
      repository.findByLastName("Bauer").forEach(bauer -> {
        log.info(bauer.toString());
      });
      // for (Customer bauer : repository.findByLastName("Bauer")) {
      //  log.info(bauer.toString());
      // }
      log.info("");
    };
  }

}

AccessingDataJpaApplication.javaファイルに追加したコードを深掘りしていきます。

①ログ出力のためのlog

AccessingDataJpaApplication.java
// 追加したコード
private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

ターミナルでログを表示するためにLogger、LoggerFactoryを用いています。
LoggerFactory.getLogger()の引数にクラスを指定してログを取得することが出来ます。

②データの登録、取得

AccessingDataJpaApplication.java
// 追加したコード
@Bean
public CommandLineRunner demo(CustomerRepository repository) {
  return (args) -> {
    // save a few customers
    repository.save(new Customer("Jack", "Bauer"));
    repository.save(new Customer("Chloe", "O'Brian"));
    repository.save(new Customer("Kim", "Bauer"));
    repository.save(new Customer("David", "Palmer"));
    repository.save(new Customer("Michelle", "Dessler"));

    // fetch all customers
    log.info("Customers found with findAll():");
    log.info("-------------------------------");
    for (Customer customer : repository.findAll()) {
      log.info(customer.toString());
    }
    log.info("");

    // fetch an individual customer by ID
    Customer customer = repository.findById(1L);
    log.info("Customer found with findById(1L):");
    log.info("--------------------------------");
    log.info(customer.toString());
    log.info("");

    // fetch customers by last name
    log.info("Customer found with findByLastName('Bauer'):");
    log.info("--------------------------------------------");
    repository.findByLastName("Bauer").forEach(bauer -> {
      log.info(bauer.toString());
    });
    // for (Customer bauer : repository.findByLastName("Bauer")) {
    //  log.info(bauer.toString());
    // }
    log.info("");
  };
}

データの登録、取得を行なっている
CommandLineRunner demo(CustomerRepository repository)というメソッドは、SpringBootがアプリ実行後に呼び出してくれます。

その中でまずは、データの登録を行なっています。
Customerをインスタンス化する際にコンストラクタの引数に文字列(firstName、lastName)を渡しています。
そしてrepositoryのsaveメソッドでその生成されたJavaオブジェクトをCustomerテーブルに登録しています。

repository.save(new Customer("Jack", "Bauer"));

次に、findAll()で全てのデータを取得しています。
拡張for文でループを回して、取得した複数のデータを引数customerで受け取り1つずつ出力しています。
出力する際にオーバーライドしたtoString()を使用しています。

for (Customer customer : repository.findAll()) {
  log.info(customer.toString());
}

次に、findById(1L)でIDが1のデータを取得しています。
これは特定の1つのデータしか取得できないので、ループを回さずに出力しています。

// fetch an individual customer by ID
Customer customer = repository.findById(1L);
log.info(customer.toString());

最後に、findByLastName("Bauer")で、lastNameの値がBauerのデータを取得しています。
このデータは複数ある可能性があるので、List型で受け取るよう定義されていましたね。

取得した複数のデータをforEach文でループを回して、引数bauerで受け取り1つずつ出力しています。
コメントアウトされている拡張for文は、こちらの書き方でも良いですよという事だと思います。

// fetch customers by last name
repository.findByLastName("Bauer").forEach(bauer -> {
    log.info(bauer.toString());
});
// for (Customer bauer : repository.findByLastName("Bauer")) {
  //  log.info(bauer.toString());
// }

3.実行してみよう!

アプリケーション実行の準備が出来たので確認しましょう。

ターミナルで以下のコマンドを入力してEnterしてください。

ターミナル
$ ./mvnw spring-boot:run

しばらくすると、ターミナルに以下の文字が出てきます。

ターミナル
Customers found with findAll():
-------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']

Customer found with findById(1L):
--------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']

Customer found with findByLastName('Bauer'):
--------------------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']

参考サイト

JPA関連アノテーションの基本として-その1-
エンティティークラスの要件
CrudRepository
【Spring Data JPA】自動実装されるメソッドの命名ルール

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TDD勉強#1環境構築した&はじめてのテスト駆動開発(July 6th, 2020)

javaの環境構築をした.

動作環境

  • visual studio code
  • windows10

vscodeのjava環境構築

下のサイトみた
https://qiita.com/takuma-jpn/items/b49785a314fb4db85775

早速Hello World!に苦戦

javaで Hello World!を表示するプログラム↓

Test.java
public class Test {
    public static void main(String[] args) {
        System.out.println("Hello.World!");
    }
}

どうもファイル名とクラス名を一致させる必要があるらしい.沼だった.
あとは,launch.jsonをつくる.フォルダを選択してプロジェクト化する(?)

maven使ってTDD動いた

下のサイトみた.
https://engineeringnote.hateblo.jp/entry/java/junit_with_maven_in_vscode

注意事項
設定からjavahomeでmavenにチェックを入れる必要がある.

そもそもjavaが分からない

classの仕組みてきな

class.java
class AA{
    AA();        //コンストラクタ(?)
    void BB(){
    AA C = new AA();   //インスタンス(?)
    C.BB()
    }
}

新しい知識(キーワード)

  • new演算子
  • assertEquals(引数1,引数2):引数が等しいかどうか調べるメソッド

おわりに

vscodeでpythonでもテスト(javaのテストをpythonに翻訳) しようとしたが,環境構築はうまくいったが,classまわりの書き方が分からず断念.
ひとまず慣れないjavaでTDDを一通り勉強していく.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Processing×Java] 関数の使いかた

この記事はプログラムの構造をProcessingを通じて理解していくための記事です。
今回は関数について書いていきます。

ezgif.com-gif-maker (4).gif

目次
0.関数の使いかた
1.あらかじめ用意されている関数
2.自分で定義してつくる関数
3.関数のモジュール化→再利用化の例

0.関数とは

0-0. 関数とは

関数は、出力装置のようなものです。
何かを受け取って、それを変換して出力します。

0-1. なぜ関数を使うのか

主な理由は、
プログラムが読みやすくなるから。
再利用できるようになるから。
(再利用については後ほど詳しく)

0-2. 関数の種類

関数には、"あらかじめ用意されている関数"と、"自分で定義してつくる関数"があります。

あらかじめ用意されている関数は、具体的には、size(),background(),line(),void setup(),void draw()...などです。

1.あらかじめ用意されている関数

Processingでは、たくさんの関数があらかじめ用意されています
size(),background(),rect(),ellipse()...など。
例えばsize()関数で、size(600,400);とすると横幅600px,縦幅400pxのウィンドウが表示されます。

ここで重要なのは、あらかじめ用意されている関数は、決められたルール通りに使う必要があるということです。

例えば、size(600,400,300,200);のようにするとエラーになります。
決められたルールは、ProcessingのReferenceを見ればわかります。

(例)size()の決められたルール

スクリーンショット 2020-07-06 11.23.34 1.png

2.自分で定義してつくる関数

プログラミングでは自分のオリジナルの関数を作ってプログラムをシンプルにすることができます。
最初は、以下の円を表示するプログラムを簡略化していきます。

maru.java
void setup(){
  size(200,200);
  background(255);
}

void draw(){
  strokeWeight(3);
  stroke(77,196,224);
  noFill();
  ellipse(100,100,30,30);
}

olympic.png

プログラムを簡略化するために、
モジュール化する
再利用可能にする
ということをしていきます。

①モジュール化する

maru_module.java
void setup(){
  size(200,200);
  background(255);
}

//何を繰り返すのか一目でわかる!
void draw(){
  //自分がつくったオリジナルの関数を実行する。
  maru();
}

//ここにまとめた!!
void maru(){
  strokeWeight(3);
  stroke(77,196,224);
  noFill();
  ellipse(100,100,30,30);
}

Point :
まとめて1つの関数とすることで、draw()関数がすっきりしてプログラムがわかりやすいものになります。

②再利用可能にする

再利用が可能とは、複数の出力が可能ということです。

maru_reuse.java
void setup(){
  size(200,200);
  background(255);
}

void draw(){
  //自分で定義した関数を使う
  //複数の円を簡単に表示できる!
  //maru(x座標,y座標,円の大きさ);
  maru(100,80,100);
  maru(100,100,50);
}

//関数の定義
//まず引数に何をとるかを決める
void maru(float x,float y,float s){
  strokeWeight(3);
  stroke(77,196,224);
  noFill();
  //引数の値を何に使うかがかいてある
  ellipse(x,y,s,s);
}

olympic01.png

Point :
再利用可能にするには、引数(パラメータ)の値を決められるようにします。
そうすれば、関数の出力値に変化をつけることができます。

そのためには
①どの値に変化をつけたいか決めて、変数で表す。

  ellipse(x,y,s,s);

データ型 変数という形で引数を定義する。

void maru(float x,float y,float s){
}

③自分で定義した関数のルールに従って、関数を使う。

  maru(100,80,100);

voidとは何か

関数の実行結果として受け取るデータを返り値といいます。

関数は基本的には、intや、floatなどの値を返します。
float型の数値を返す関数の例↓

float_function.java
void setup(){
  //自分で定義したaverage()関数を使って、変数fに平均値を代入する。
  float f = average(12.0,6.0);
  //fの値を表示する。
  println(f);
}

//2つの値の平均値を求めることができる関数average()を定義する。
float average(float num1,float num2){
  //変数avに、2つの値の平均値を代入できるように式をつくる
  float av = (num1 + num2) / 2.0;
  //返り値にfloat型の数値を返す
  return av;
}
9.0

しかし、ellipse()など、図形を描く関数は、値を返しません。
このように関数が返り値を返さない場合にvoidを使います。

Point :
返り値を返さない関数は通常はそれ自身のみでつかわれます。(つまりvoidは書かれない)
background(),fill(),rect()....など。
{}を使って処理の内容を決める関数には、voidをつけます。
void setup(){},void draw(){}...など。

3.関数のモジュール化→再利用化の例

◯桜の花びらを描くプログラム

sakura.java
int x = 300;
int y = 300;
//回転するはやさを決める変数rを定義する。
float r = 30.0;
//桜の透明度を決める変数aを定義する。
int a = 150;

void setup(){
size(600,600);
}

void draw(){
  background(255);
  //popMatrixまでの描写を1つにまとめて出力する。
  pushMatrix();
  //座標の基準点(原点)を(x,y)に移動する
  translate(x,y);
  //どのくらい回転するかを変数rを使って決める。
  rotate(frameCount/r);
  //桜の描写
  for(int i = 0;i < 5;i++){
    rotate(TWO_PI * 1/5);
    noStroke();
    fill(255,50,80,a);
    stroke(225,50,80,100);
    bezier(0,0,35,-20,35,-52,8,-80);
    bezier(0,0,-35,-20,-35,-52,-8,-80);
    stroke(225,50,80,30);
    triangle(0,0,8,-80,0,-75);
    triangle(0,0,-8,-80,0,-75);
  }
  fill(200,50,100,200);
  ellipse(0,0,15,15);
  //桜の描写をまとめて出力する。
  popMatrix();
}

ezgif.com-gif-maker (3).gif

◯桜の花びらを描くプログラム(モジュール化する)

sakura_module.java
int x = 300;
int y = 300;
float r = 30.0;
int a = 150;

void setup(){
size(600,600);
}

//draw()関数の中がすっきりしてみやすくなった。
void draw(){
  background(255);
  //自分で定義した関数を使う!
  sakura();
}

//桜の花びらに関する関数を定義する。
void sakura(){
  pushMatrix();
  translate(x,y);
  rotate(frameCount/r);
  for(int i = 0;i < 5;i++){
    rotate(TWO_PI * 1/5);
    noStroke();
    fill(255,50,80,a);
    stroke(225,50,80,100);
    bezier(0,0,35,-20,35,-52,8,-80);
    bezier(0,0,-35,-20,-35,-52,-8,-80);
    stroke(225,50,80,30);
    triangle(0,0,8,-80,0,-75);
    triangle(0,0,-8,-80,0,-75);
  }
  fill(200,50,100,200);
  ellipse(0,0,15,15);
  popMatrix();
}

◯桜の花びらを描くプログラム(再利用可能にする)

sakura_reuse.java
void setup(){
size(600,600);
}

void draw(){
  background(255);
  //パラメータを変えた関数を3つ出力する
  sakura(400,200,30,150);
  sakura(100,300,-40,100);
  sakura(380,400,60,50);
}
//オリジナルの関数を定義する
//引数を、データ型と変数の形で定義する。
void sakura(float x,float y,float r,float a){

  pushMatrix();
  translate(x,y);
  rotate(frameCount/r);
  for(int i = 0;i < 5;i++){
    rotate(TWO_PI * 1/5);
    noStroke();
    fill(255,50,80,a);
    stroke(225,50,80,100);
    bezier(0,0,35,-20,35,-52,8,-80);
    bezier(0,0,-35,-20,-35,-52,-8,-80);
    stroke(225,50,80,30);
    triangle(0,0,8,-80,0,-75);
    triangle(0,0,-8,-80,0,-75);
  }
  fill(200,50,100,200);
  ellipse(0,0,15,15);
  popMatrix();
}

ezgif.com-gif-maker (4).gif

最後に

読んでいただきありがとうございました。
より良い記事にしていくために御意見、ご指摘のほどよろしくお願いいたします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む