第13章 Business Central のフォーム

フォームは、HTML として定義されたページのレイアウト定義であり、プロセスおよびタスクのインスタンス化の間にユーザーにダイアログウィンドウとして表示されます。タスクフォームはプロセスとタスクインスタンスの両方の実行のためにユーザーからデータを取得しますが、プロセスフォームはプロセス変数から入力と出力を受け取ります。

入力は、Data Input Assignment を使用してタスクにマッピングされ、タスク内で使用できます。タスクが完了すると、データは Data Output Assignment としてマッピングされ、データを親プロセスインスタンスに提供します。

13.1. Form Modeler

Red Hat Process Automation Manager は、Form Modeler と呼ばれるフォームを定義するためのカスタムエディターを提供します。Form Modeler を使用すると、コードを記述せずに、データオブジェクトのフォーム、タスクフォーム、およびプロセス開始フォームを生成できます。Form Modeler には、複数のデータタイプをバインドするためのウィジェットライブラリーと、フォームの値が変更されたときに通知を送信するコールバックメカニズムが含まれています。Form Modeler は、Bean ベースの検証を使用し、フォームフィールドの静的または動的モデルへのバインドをサポートします。

Form Modeler には以下の機能が含まれています。

  • フォームのフォームモデリングユーザーインターフェース
  • データモデルまたは Java オブジェクトからのフォーム自動生成
  • Java オブジェクトのデータバインディング
  • 公式と式
  • カスタマイズされたフォームレイアウト
  • 埋め込みフォーム

Form Modeler には、フォームを作成するためにキャンバスに配置する定義済みのフィールドタイプが付属します。

図13.1 住宅ローンの申し込みフォームの例

5011

13.2. Business Central でのプロセスフォームおよびタスクフォームの生成

プロセスをインスタンス化したときに、プロセスをインスタンス化したユーザーに表示されるビジネスプロセスからプロセスフォームを生成できます。また、ビジネスプロセスからタスクフォームを生成することもできます。このタスクフォームは、実行フローがタスクに到達すると、ユーザータスクのインスタンス化時にユーザータスクのアクターに表示されます。

手順

  1. Business Central で、MenuDesignProjects に移動します。
  2. プロジェクト名をクリックしてアセットビューを開いてから、ビジネスプロセス名をクリックします。
  3. プロセスデザイナーで、フォームを作成するプロセスタスクをクリックします (該当する場合)。
  4. 右上のツールバーで、Form Generation アイコンをクリックして、生成するフォームを選択します。

    • Generate process form: プロセス全体のフォームを生成します。これは、プロセスインスタンスの起動時にユーザーが入力する必要がある初期フォームです。
    • Generate all forms: プロセス全体およびすべてのユーザータスクのフォームを生成します。
    • Generate forms for selection: 選択したユーザータスクノードのフォームを生成します。

    図13.2 フォーム生成メニュー

    auto form create

    フォームは、プロジェクトのルートディレクトリーに作成されます。

  5. Business Central で、プロジェクトのルートディレクトリーに移動して新しいフォーム名をクリックし、Form Modeler を使用して要件に合わせてフォームをカスタマイズします。

13.3. Business Central での手動によるフォームの作成

プロジェクトアセットビューから、タスクおよびプロセスフォームを手動で作成できます。これは、ビジネスプロセスからフォームを生成することを選択せずにフォームを生成する別の方法です。たとえば、Form Modeler は外部データオブジェクトからのフォームの作成をサポートするようになりました。

手順

  1. Business Central で、MenuDesignProjects に移動して、プロジェクト名をクリックします。
  2. Add AssetForm をクリックします。
  3. Create new Form ウィンドウで、以下の情報を入力します。

    • フォーム名 (一意である必要があります)
    • パッケージ名
    • モデルタイプ: Business Process または Data Object のいずれかを選択します。

      • Business Process モデルタイプの場合、Select Process ドロップダウンメニューからビジネスプロセスを選択し、Select Form ドロップダウンメニューから作成するフォームを選択します。
      • Data Object モデルタイプの場合、Select Data Object from Project のドロップダウンメニューから、プロジェクトデータオブジェクトの 1 つを選択します。
  4. OK をクリックして、Form Modeler を開きます。
  5. Form Modeler の左側の Components ビューで、Model Fields および Form Controls メニューを展開し、必要なフィールドとフォームコントロールをキャンバスにドラッグして新しいフォームを作成します。
  6. Save をクリックして変更を保存します。

13.4. フォームまたはプロセスでのドキュメントの添付

Red Hat Process Automation Manager は、Document フォームフィールドを使用したフォームでのドキュメントの添付をサポートしています。Document フォームフィールドを使用すると、フォームまたはプロセスの一部として必要なドキュメントをアップロードできます。

フォームおよびプロセスでドキュメントの添付を有効にするには、以下の手順を実行します。

  1. ドキュメントマーシャリング戦略を設定します。
  2. ビジネスプロセスでドキュメント変数を作成します。
  3. タスクの入力と出力をドキュメント変数にマッピングします。

13.4.1. ドキュメントマーシャリング戦略の設定

プロジェクトのドキュメントマーシャリング戦略により、フォームおよびプロセスで使用するドキュメントの保存場所が決まります。Red Hat Process Automation Manager のデフォルトのドキュメントマーシャリング戦略は org.jbpm.document.marshalling.DocumentMarshallingStrategy です。この戦略では、PROJECT_HOME/docs フォルダーにドキュメントをローカルに保存する DocumentStorageServiceImpl クラスを使用します。Business Central または kie-deployment-descriptor.xml ファイルのプロジェクトに、このドキュメントマーシャリング戦略またはカスタムドキュメントマーシャリング戦略を設定できます。

手順

  1. Business Central で、MenuDesignProjects に移動します。
  2. プロジェクトを選択します。プロジェクトの Assets ウィンドウが開きます。
  3. プロジェクトの Settings タブをクリックします。

    図13.3 設定タブ

    Selecting the settings tab
  4. DeploymentsMarshalling StrategiesAdd Marshalling Strategy をクリックします。
  5. Name フィールドにドキュメントマーシャリング戦略の識別子を入力し、Resolver のドロップダウンメニューで、対応するリゾルバータイプを選択します。

    • 1 つのドキュメントの場合: ドキュメントマーシャリング戦略として org.jbpm.document.marshalling.DocumentMarshallingStrategy を入力し、リゾルバータイプを Reflection に設定します。
    • 複数のドキュメントの場合: ドキュメントマーシャリング戦略として new org.jbpm.document.marshalling.DocumentCollectionImplMarshallingStrategy(new org.jbpm.document.marshalling.DocumentMarshallingStrategy()) を入力し、リゾルバータイプを MVEL に設定します。
    • カスタムドキュメントサポートの場合: カスタムドキュメントマーシャリング戦略の識別子を入力し、関連するリゾルバータイプを選択します。
  6. Test をクリックして、デプロイメント記述子ファイルを検証します。
  7. Deploy をクリックして、更新されたプロジェクトをビルドおよびデプロイします。

    または、Business Central を使用していない場合は、PROJECT_HOME/src/main/resources/META_INF/kie-deployment-descriptor.xml (該当する場合) に移動し、必要な <marshalling-strategies> 要素を使用してデプロイメント記述子ファイルを編集します。

  8. Save をクリックします。

複数のドキュメントのドキュメントマーシャリング戦略を使用したデプロイメント記述子ファイルの例

<deployment-descriptor
    xsi:schemaLocation="http://www.jboss.org/jbpm deployment-descriptor.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <persistence-unit>org.jbpm.domain</persistence-unit>
  <audit-persistence-unit>org.jbpm.domain</audit-persistence-unit>
  <audit-mode>JPA</audit-mode>
  <persistence-mode>JPA</persistence-mode>
  <runtime-strategy>SINGLETON</runtime-strategy>
  <marshalling-strategies>
    <marshalling-strategy>
      <resolver>mvel</resolver>
      <identifier>new org.jbpm.document.marshalling.DocumentCollectionImplMarshallingStrategy(new org.jbpm.document.marshalling.DocumentMarshallingStrategy());</identifier>
    </marshalling-strategy>
  </marshalling-strategies>

13.4.1.1. コンテンツ管理システム (CMS) にカスタムドキュメントマーシャリング戦略を使用する

プロジェクトのドキュメントマーシャリング戦略により、フォームおよびプロセスで使用するドキュメントの保存場所が決まります。Red Hat Process Automation Manager のデフォルトのドキュメントマーシャリング戦略は org.jbpm.document.marshalling.DocumentMarshallingStrategy です。この戦略では、PROJECT_HOME/docs フォルダーにドキュメントをローカルに保存する DocumentStorageServiceImpl クラスを使用します。集中型のコンテンツ管理システム (CMS) などのカスタムの場所にフォームおよびプロセスドキュメントを保存する場合は、カスタムドキュメントマーシャリング戦略をプロジェクトに追加します。このドキュメントマーシャリング戦略は、Business Central または kie-deployment-descriptor.xml ファイルで直接設定できます。

手順

  1. org.kie.api.marshalling.ObjectMarshallingStrategy インターフェースの実装を含むカスタムマーシャリング戦略 .java ファイルを作成します。このインターフェースを使用すると、カスタムドキュメントマーシャリング戦略に必要な変数の永続性を実装できます。

    このインターフェースの以下のメソッドは、戦略の作成に役立ちます。

    • boolean accept(Object object): 指定されたオブジェクトを戦略でマーシャリングできるかどうかを決定します
    • byte[] marshal(Context context, ObjectOutputStream os, Object object): 指定されたオブジェクトをマーシャリングし、マーシャリングされたオブジェクトを byte[] として返します
    • Object unmarshal(Context context, ObjectInputStream is, byte[] object, ClassLoader classloader): 受信したオブジェクトを byte[] として読み取り、マーシャリングされていないオブジェクトを返します
    • void write(ObjectOutputStream os, Object object): 下位互換性のために提供されている marshal メソッドと同じです
    • Object read(ObjectInputStream os): 下位互換性のために提供されている unmarshal メソッドと同じです

    以下のコードサンプルは、コンテンツ管理相互運用サービス (CMIS) システムからデータを保存および取得するための ObjectMarshallingStrategy 実装例です。

    CMIS システムからデータを保存および取得するための実装例

    package org.jbpm.integration.cmis.impl;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.HashMap;
    
    import org.apache.chemistry.opencmis.client.api.Folder;
    import org.apache.chemistry.opencmis.client.api.Session;
    import org.apache.chemistry.opencmis.commons.data.ContentStream;
    import org.apache.commons.io.IOUtils;
    import org.drools.core.common.DroolsObjectInputStream;
    import org.jbpm.document.Document;
    import org.jbpm.integration.cmis.UpdateMode;
    
    import org.kie.api.marshalling.ObjectMarshallingStrategy;
    
    public class OpenCMISPlaceholderResolverStrategy extends OpenCMISSupport implements ObjectMarshallingStrategy {
    
    	private String user;
    	private String password;
    	private String url;
    	private String repository;
    	private String contentUrl;
    	private UpdateMode mode = UpdateMode.OVERRIDE;
    
    	public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository) {
    		this.user = user;
    		this.password = password;
    		this.url = url;
    		this.repository = repository;
    	}
    
    	public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, UpdateMode mode) {
    		this.user = user;
    		this.password = password;
    		this.url = url;
    		this.repository = repository;
    		this.mode = mode;
    	}
    
    	   public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, String contentUrl) {
    	        this.user = user;
    	        this.password = password;
    	        this.url = url;
    	        this.repository = repository;
    	        this.contentUrl = contentUrl;
    	    }
    
    	    public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, String contentUrl, UpdateMode mode) {
    	        this.user = user;
    	        this.password = password;
    	        this.url = url;
    	        this.repository = repository;
    	        this.contentUrl = contentUrl;
    	        this.mode = mode;
    	    }
    
    	public boolean accept(Object object) {
    		if (object instanceof Document) {
    			return true;
    		}
    		return false;
    	}
    
    	public byte[] marshal(Context context, ObjectOutputStream os, Object object) throws IOException {
    		Document document = (Document) object;
    		Session session = getRepositorySession(user, password, url, repository);
    		try {
    			if (document.getContent() != null) {
    				String type = getType(document);
    				if (document.getIdentifier() == null || document.getIdentifier().isEmpty()) {
    					String location = getLocation(document);
    
    					Folder parent = findFolderForPath(session, location);
    					if (parent == null) {
    						parent = createFolder(session, null, location);
    					}
    					org.apache.chemistry.opencmis.client.api.Document doc = createDocument(session, parent, document.getName(), type, document.getContent());
    					document.setIdentifier(doc.getId());
    					document.addAttribute("updated", "true");
    				} else {
    					if (document.getContent() != null && "true".equals(document.getAttribute("updated"))) {
    						org.apache.chemistry.opencmis.client.api.Document doc = updateDocument(session, document.getIdentifier(), type, document.getContent(), mode);
    
    						document.setIdentifier(doc.getId());
    						document.addAttribute("updated", "false");
    					}
    				}
    			}
    			ByteArrayOutputStream buff = new ByteArrayOutputStream();
    	        ObjectOutputStream oos = new ObjectOutputStream( buff );
    	        oos.writeUTF(document.getIdentifier());
    	        oos.writeUTF(object.getClass().getCanonicalName());
    	        oos.close();
    	        return buff.toByteArray();
    		} finally {
    			session.clear();
    		}
    	}
    
    	public Object unmarshal(Context context, ObjectInputStream ois, byte[] object, ClassLoader classloader) throws IOException, ClassNotFoundException {
    		DroolsObjectInputStream is = new DroolsObjectInputStream( new ByteArrayInputStream( object ), classloader );
    		String objectId = is.readUTF();
    		String canonicalName = is.readUTF();
    		Session session = getRepositorySession(user, password, url, repository);
    		try {
    			org.apache.chemistry.opencmis.client.api.Document doc = (org.apache.chemistry.opencmis.client.api.Document) findObjectForId(session, objectId);
    			Document document = (Document) Class.forName(canonicalName).newInstance();
    			document.setAttributes(new HashMap<String, String>());
    
    			document.setIdentifier(objectId);
    			document.setName(doc.getName());
    			document.setLastModified(doc.getLastModificationDate().getTime());
    			document.setSize(doc.getContentStreamLength());
    			document.addAttribute("location", getFolderName(doc.getParents()) + getPathAsString(doc.getPaths()));
    			if (doc.getContentStream() != null && contentUrl == null) {
    				ContentStream stream = doc.getContentStream();
    				document.setContent(IOUtils.toByteArray(stream.getStream()));
    				document.addAttribute("updated", "false");
    				document.addAttribute("type", stream.getMimeType());
    			} else {
    			    document.setLink(contentUrl + document.getIdentifier());
    			}
    			return document;
    		} catch(Exception e) {
    			throw new RuntimeException("Cannot read document from CMIS", e);
    		} finally {
    			is.close();
    			session.clear();
    		}
    	}
    
    	public Context createContext() {
    		return null;
    	}
    
    	// For backward compatibility with previous serialization mechanism
    	public void write(ObjectOutputStream os, Object object) throws IOException {
    		Document document = (Document) object;
    		Session session = getRepositorySession(user, password, url, repository);
    		try {
    			if (document.getContent() != null) {
    				String type = document.getAttribute("type");
    				if (document.getIdentifier() == null) {
    					String location = document.getAttribute("location");
    
    					Folder parent = findFolderForPath(session, location);
    					if (parent == null) {
    						parent = createFolder(session, null, location);
    					}
    					org.apache.chemistry.opencmis.client.api.Document doc = createDocument(session, parent, document.getName(), type, document.getContent());
    					document.setIdentifier(doc.getId());
    					document.addAttribute("updated", "false");
    				} else {
    					if (document.getContent() != null && "true".equals(document.getAttribute("updated"))) {
    						org.apache.chemistry.opencmis.client.api.Document doc = updateDocument(session, document.getIdentifier(), type, document.getContent(), mode);
    
    						document.setIdentifier(doc.getId());
    						document.addAttribute("updated", "false");
    					}
    				}
    			}
    			ByteArrayOutputStream buff = new ByteArrayOutputStream();
    	        ObjectOutputStream oos = new ObjectOutputStream( buff );
    	        oos.writeUTF(document.getIdentifier());
    	        oos.writeUTF(object.getClass().getCanonicalName());
    	        oos.close();
    		} finally {
    			session.clear();
    		}
    	}
    
    	public Object read(ObjectInputStream os) throws IOException, ClassNotFoundException {
    		String objectId = os.readUTF();
    		String canonicalName = os.readUTF();
    		Session session = getRepositorySession(user, password, url, repository);
    		try {
    			org.apache.chemistry.opencmis.client.api.Document doc = (org.apache.chemistry.opencmis.client.api.Document) findObjectForId(session, objectId);
    			Document document = (Document) Class.forName(canonicalName).newInstance();
    
    			document.setIdentifier(objectId);
    			document.setName(doc.getName());
    			document.addAttribute("location", getFolderName(doc.getParents()) + getPathAsString(doc.getPaths()));
    			if (doc.getContentStream() != null) {
    				ContentStream stream = doc.getContentStream();
    				document.setContent(IOUtils.toByteArray(stream.getStream()));
    				document.addAttribute("updated", "false");
    				document.addAttribute("type", stream.getMimeType());
    			}
    			return document;
    		} catch(Exception e) {
    			throw new RuntimeException("Cannot read document from CMIS", e);
    		} finally {
    			session.clear();
    		}
    	}
    
    }

  2. Business Central で、MenuDesignProjects に移動します。
  3. プロジェクトの名前をクリックしてから、Settings をクリックします。

    図13.4 設定タブ

    Selecting the settings tab
  4. DeploymentsMarshalling StrategiesAdd Marshalling Strategy をクリックします。
  5. Name フィールドに、この例の org.jbpm.integration.cmis.impl.OpenCMISPlaceholderResolverStrategy のように、カスタムドキュメントマーシャリング戦略の識別子を入力します。
  6. この例の Reflection のように、Resolver ドロップダウンメニューから関連オプションを選択します。
  7. Test をクリックして、デプロイメント記述子ファイルを検証します。
  8. Deploy をクリックして、更新されたプロジェクトをビルドおよびデプロイします。

    または、Business Central を使用していない場合は、PROJECT_HOME/src/main/resources/META_INF/kie-deployment-descriptor.xml (該当する場合) に移動し、必要な <marshalling-strategies> 要素を使用してデプロイメント記述子ファイルを編集します。

    カスタムドキュメントマーシャリング戦略を使用したデプロイメント記述子ファイルの例

    <deployment-descriptor
        xsi:schemaLocation="http://www.jboss.org/jbpm deployment-descriptor.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <persistence-unit>org.jbpm.domain</persistence-unit>
      <audit-persistence-unit>org.jbpm.domain</audit-persistence-unit>
      <audit-mode>JPA</audit-mode>
      <persistence-mode>JPA</persistence-mode>
      <runtime-strategy>SINGLETON</runtime-strategy>
      <marshalling-strategies>
        <marshalling-strategy>
          <resolver>reflection</resolver>
          <identifier>
            org.jbpm.integration.cmis.impl.OpenCMISPlaceholderResolverStrategy
          </identifier>
        </marshalling-strategy>
      </marshalling-strategies>

  9. カスタムの場所に保存されたドキュメントをフォームおよびプロセスに添付できるようにするには、関連するプロセスでドキュメント変数を作成し、Business Central でそのドキュメント変数にタスクの入力と出力をマッピングします。

13.4.2. ビジネスプロセスでのドキュメント変数の作成

ドキュメントマーシャリング戦略を設定したら、関連プロセスでドキュメント変数を作成して、ドキュメントをヒューマンタスクにアップロードし、Business Central の Process Instances ビューにドキュメントを表示できるようにします。

前提条件

手順

  1. Business Central で、MenuDesignProjects に移動します。
  2. プロジェクト名をクリックしてアセットビューを開き、ビジネスプロセス名をクリックします。
  3. キャンバスをクリックし、ウィンドウの右側にある diagram properties をクリックして、Diagram properties パネルを開きます。
  4. Process Data を展開し、 6176 をクリックして、以下の値を入力します。

    • Name: document
    • Custom Type: 1 つのドキュメントの場合は org.jbpm.document.Document、複数のドキュメントの場合は org.jbpm.document.DocumentCollection

13.4.3. ドキュメント変数へのタスクの入力と出力のマッピング

タスクフォーム内の添付ファイルを表示または変更する場合は、タスクの入力および出力内に割り当てを作成します。

前提条件

  • 1 つ以上のユーザータスクを持つビジネスプロセスアセットを含むプロジェクトがある。

手順

  1. Business Central で、MenuDesignProjects に移動します。
  2. プロジェクト名をクリックしてアセットビューを開き、ビジネスプロセス名をクリックします。
  3. ユーザータスクをクリックし、ウィンドウの右側にある diagram properties をクリックして Diagram properties パネルを開きます。
  4. Implementation/Execution を展開し、Assignments の横の btn assign をクリックして、Data I/O ウィンドウを開きます。
  5. Data Inputs and Assignments の横の Add をクリックして、以下の値を入力します。

    • Name: taskdoc_in
    • Data Type: 1 つのドキュメントの場合は org.jbpm.document.Document、複数のドキュメントの場合は org.jbpm.document.DocumentCollection
    • Source: document
  6. Data Outputs and Assignments の横の Add をクリックし、以下の値を入力します。

    • Name: taskdoc_out
    • Data Type: 1 つのドキュメントの場合は org.jbpm.document.Document、複数のドキュメントの場合は org.jbpm.document.DocumentCollection
    • Target: document

    Source および Target フィールドには、前に作成したプロセス変数の名前が含まれています。

  7. Save をクリックします。