カスタム トリガーの作成 (例 1)

パッケージ SDK は、定義済みの条件に基づいてアクションを自動化するカスタム トリガーを構築するためのツールを提供します。

このセクションでは、Automation Anywhere のパッケージ SDK を使用して、インターバル トリガーを作成する方法について説明します。 「TriggerDemo」というサンプル クラスを使用して、その機能を順を追って説明します。 最後には、パッケージ SDK を使用して独自のカスタム トリガーを構築する方法について、しっかりと理解することができます。

手順

  1. 依存関係とパッケージ: コード サンプルはさまざまなインポートを利用し、パッケージ com.automationanywhere.botcommand.samples.trigger 内で構成されています。
  2. 注釈: コードでは、パッケージ SDK が提供するいくつかの注釈を利用して、トリガーを定義および設定します。 こうした注釈には、以下のものが含まれます。
    1. @BotCommand: このクラスがトリガーを表していることを指定します。 これは、行 @BotCommand(commandType = BotCommand.CommandType.Trigger) を使用して指定します。 それがコマンド タイプ Trigger であることを指定すると、Bot エディター内の [トリガー] セクションに表示されます。
    2. @CommandPkg: ラベル、説明、アイコン、リターン タイプなど、トリガーに関するメタデータを提供します。 次のサンプルに示すように、リターン タイプは常に [レコード] に設定されています。
    3. @TriggerId: 各トリガー インスタンスに割り当てられた一意の識別子を示します。
    4. @TriggerConsumer: トリガー条件が満たされたときに呼び出される consumer 関数を指定します。
    5. @StartListen: トリガーの起動を担当するメソッドをマークします。
      ヒント: @StartListen は、トリガーを実行するために使用され、Bot の場合の @Execute に似ています。
    6. @StopAllTriggers: すべてのトリガーをキャンセルするために使用されるメソッドを識別します。
    7. @StopListen: 特定のトリガーのキャンセルを担当するメソッドを識別します。
  3. トリガーの実行: トリガーの実行ロジックは、@StartListen 注釈を使用して startTrigger メソッドで実装されます。 この例では、TimerTask は、ユーザーが定義した一定の間隔で実行するようにスケジュール設定されています。 スケジュール設定された時間になると、TimerTaskrun メソッドが実行され、consumer.accept がトリガーされます。 consumer は、getRecordValue メソッドから返された RecordValue を受け入れます。
    ヒント: RecordValue は、Bot ロジック内でも使用できます。
  4. getRecordValue Method: getRecordValue メソッドは RecordValue オブジェクトを作成し、それにスキーマと値のリストを入力します。 この例では、スキーマ triggerType が、対応する値 Interval Trigger とともに追加されます。
  5. StopListenStopAllTriggers Methods: これらのメソッドには、それぞれ @StopListen@StopAllTriggers という注釈が付けられています。 これらには、トリガー タスクをキャンセルする役割と、タスク マップから削除する役割があります。
  6. その他のヘルパー メソッド: コードには、triggerUid 変数および consumer 変数に対する getter メソッドと setter メソッドも含まれています。
package com.automationanywhere.botcommand.samples.trigger;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

import javax.sql.DataSource;

import com.automationanywhere.botcommand.data.Value;
import com.automationanywhere.botcommand.data.impl.RecordValue;
import com.automationanywhere.botcommand.data.impl.StringValue;
import com.automationanywhere.botcommand.data.model.Schema;
import com.automationanywhere.botcommand.data.model.record.Record;
import com.automationanywhere.botcommand.samples.exceptions.DemoException;
import com.automationanywhere.commandsdk.annotations.*;
import org.apache.commons.dbcp2.BasicDataSource;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.automationanywhere.botcommand.exception.BotCommandException;
import com.automationanywhere.commandsdk.annotations.rules.GreaterThan;
import com.automationanywhere.commandsdk.annotations.rules.NotEmpty;
import com.automationanywhere.commandsdk.annotations.rules.NumberInteger;
import com.automationanywhere.commandsdk.model.AttributeType;
import com.automationanywhere.commandsdk.model.DataType;
import com.automationanywhere.core.security.SecureString;

import static com.automationanywhere.commandsdk.model.DataType.RECORD;

/**
 * This example is an extension of the timer based trigger {@link TriggerDemo} and demonstrates the
 * pull mechanism.
 * Trigger will check the DB at regular interval and if the records returned by
 * user provided SQL is more than 0 then it will get triggered.
 * NOTE 1: This class is for illustrative purpose only not safe for use in production.
 * NOTE 2: Please add the valid DB driver in build gradle to run this example.
 * 
 */
@BotCommand(commandType = BotCommand.CommandType.Trigger)
@CommandPkg(label = "JDBC Query Trigger", description = "JDBC Query Trigger", icon = "jdbc.svg", name = "jdbcQueryTrigger",
		return_type = RECORD, return_name = "TriggerData", return_description = "Available keys: triggerType")
public class DBStatus {
	
	private static Logger logger = LogManager.getLogger(DBStatus.class);
	
	
	// Map storing multiple tasks
	private static final Map<String, TimerTask> taskMap = new ConcurrentHashMap<>();
	private static final Timer TIMER = new Timer(true);

	@TriggerId
	private String triggerUid;
	@TriggerConsumer
	private Consumer consumer;

	/*
	 * Starts the trigger.
	 */
	@StartListen
	public void startTrigger(
			@Idx(index="1", type = AttributeType.TEXT)
			@Pkg(label = "Please provide the database driver class")
			@NotEmpty
			String driverClassName,
			
			@Idx(index="2", type = AttributeType.TEXT)
			@Pkg(label = "Please provide the Jdbc connection string")
			@NotEmpty
			String jdbcUrl,
			
			@Idx(index="3", type = AttributeType.TEXT)
			@Pkg(label = "Please provide the user Name")
			@NotEmpty
			String userName,
			
			@Idx(index="4", type = AttributeType.CREDENTIAL)
			@Pkg(label = "Please provide the password")
			@NotEmpty
			SecureString password,
			
			@Idx(index="5", type = AttributeType.TEXT)
			@Pkg(label = "Please provide the SQL to check the records")
			@NotEmpty
			String sqlQuery,
			
			@Idx(index = "6", type = AttributeType.NUMBER)
			@Pkg(label = "Please provide the interval to query in seconds", default_value = "300", default_value_type = DataType.NUMBER)
			@GreaterThan("0")
			@NumberInteger
			@NotEmpty
			Double interval) {
		
		DataSource dataSource = getDataSource(driverClassName, jdbcUrl, userName, password);
		
		TimerTask timerTask = new TimerTask() {

			@Override
			public void run() {
				logger.debug("checking DB");
				try {
					if(checkRecordsExist(dataSource.getConnection(), sqlQuery)){
						consumer.accept(getRecordValue());
						return;
					}
				} catch (SQLException e) {
					logger.warn(e.getMessage(),e);
					logger.warn("Trigger is still running.");
				}
				logger.debug("no records found");

			}
		};

		taskMap.put(this.triggerUid, timerTask);
		TIMER.schedule(timerTask, interval.longValue(), interval.longValue());
	}

	private RecordValue getRecordValue() {
		List<Schema> schemas = new LinkedList<>();
		List<Value> values = new LinkedList<>();
		schemas.add(new Schema("triggerType"));
		values.add(new StringValue("DBStatus"));

		RecordValue recordValue = new RecordValue();
		recordValue.set(new Record(schemas,values));
		return recordValue;
	}
	/*
	 * Cancel all the task and clear the map.
	 */
	@StopAllTriggers
	public void stopAllTriggers() {
		taskMap.forEach((k, v) -> {
			if (v.cancel()) {
				taskMap.remove(k);
			}
		});
	}

	/*
	 * Cancel the task and remove from map
	 *
	 * @param triggerUid
	 */
	@StopListen
	public void stopListen(String triggerUid) {
		if (taskMap.get(triggerUid).cancel()) {
			taskMap.remove(triggerUid);
		}
	}

    public static DataSource getDataSource(String driverClassName, String url, String userName,SecureString password) {
    	BasicDataSource ds = new BasicDataSource();
    	ds.setDriverClassName(driverClassName);
    	ds.setUrl(url);
    	ds.setUsername(userName);
    	ds.setPassword(password.getInsecureString());
        return ds;
    }
	
    public static boolean checkRecordsExist(Connection con, String query)
    	    throws SQLException {
			
    	    Statement stmt = null;
    	    try {
    	        stmt = con.createStatement();
    	        ResultSet rs = stmt.executeQuery(query);
    	        rs.last();
    	        if(rs.getRow() > 0)
    	        	return true;
    	    } catch (SQLException e ) {
    	        throw new DemoException("Problem running statemnt", e);
    	    } finally {
    	        if (stmt != null) { stmt.close(); }
    	    }
    	    
    	    return false;
    	}
    
	public String getTriggerUid() {
		return triggerUid;
	}

	public void setTriggerUid(String triggerUid) {
		this.triggerUid = triggerUid;
	}

	public Consumer getConsumer() {
		return consumer;
	}

	public void setConsumer(Consumer consumer) {
		this.consumer = consumer;
	}
}

次のステップ

上記のコード サンプルでは、トリガーの作成と管理に使用されるさまざまなメソッドと注釈を説明しています。 コードとその機能を理解することで、パッケージ SDK を使用した独自のインターバル トリガーを作成できるようになります。 さまざまな間隔やトリガー アクションを試して、ビジネス プロセスを効果的に自動化します。

上記の記事はあくまでサンプルであり、固有の要件や対象者に合わせて、さらに調整してカスタマイズする必要があります。