사용자 정의 트리거 생성(예 1)

패키지 SDK는 미리 정의된 조건에 따라 작업을 자동화하는 사용자 정의 트리거를 구축하는 도구를 제공합니다.

이 섹션에서는 Automation Anywhere의 패키지 SDK를 사용하여 간격 트리거를 생성하는 방법을 학습하겠습니다. TriggerDemo라는 샘플 클래스는 기능을 단계별로 설명하는 데 사용됩니다. 마지막에는 패키지 SDK를 사용하여 사용자 정의 트리거를 구축하는 방법을 확실하게 이해하게 될 것입니다.

프로시저

  1. 종속성 및 패키지: 코드 샘플은 다양한 가져오기를 활용하고 패키지 com.automationanywhere.botcommand.samples.trigger 내에서 구성됩니다.
  2. 주석 기호: 이 코드는 패키지 SDK에서 제공하는 여러 주석 기호를 활용하여 트리거를 정의하고 구성합니다. 이러한 주석 기호에는 다음이 포함됩니다.
    1. @BotCommand: 이 클래스가 트리거를 나타내도록 지정합니다. @BotCommand(commandType = BotCommand.CommandType.Trigger) 줄을 사용하여 이를 지정합니다. Trigger 명령 유형이라고 지정할 경우 봇 편집기 내의 트리거 섹션에 해당 명령이 표시됩니다.
    2. @CommandPkg: 레이블, 설명, 아이콘, 반환 유형과 같은 트리거에 대한 메타데이터를 제공합니다. 반환 유형은 다음 샘플에 표시된 것과 같이 항상 RECORD로 설정됩니다.
    3. @TriggerId: 각 트리거 인스턴스에 할당된 고유 식별자를 나타냅니다.
    4. @TriggerConsumer: 트리거 조건이 충족될 때 호출할 소비자 함수를 지정합니다.
    5. @StartListen: 트리거 시작을 담당하는 메소드를 표시합니다.
      팁: @StartListen은 트리거를 실행하는 데 사용되며 봇의 경우 @Execute와 유사합니다.
    6. @StopAllTriggers: 모든 트리거를 취소하는 데 사용되는 메소드를 식별합니다.
    7. @StopListen: 특정 트리거 취소를 담당하는 메소드를 식별합니다.
  3. 트리거 실행: 트리거 실행 로직은 @StartListen 주석을 사용하는 startTrigger 메소드에서 구현됩니다. 이 예에서 TimerTask는 사용자가 정의한 일정한 간격으로 실행되도록 예약됩니다. 예약시간이 되면, TimerTaskrun 메서드가 실행되어 consumer.accept을 트리거합니다. 소비자getRecordValue 메소드에서 반환된 RecordValue를 수락합니다.
    팁: RecordValue도 봇 로직 내에서 사용할 수 있습니다.
  4. getRecordValue 메서드: getRecordValue 메소드는 RecordValue 객체를 생성하고 이를 스키마 및 값에 대한 목록으로 채웁니다. 이 예에서 스키마 triggerType은 해당 값 간격 트리거와 함께 추가됩니다.
  5. StopListenStopAllTriggers 메서드: 이러한 메소드는 각각 @StopListen@StopAllTriggers로 주석 처리됩니다. 트리거 태스크를 취소하고 작업 맵에서 제거할 책임이 있습니다.
  6. 추가 도우미 메소드: 코드에는 triggerUidconsumer 변수를 위한 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를 사용하여 자신만의 간격 트리거를 생성할 수 있습니다. 다양한 간격으로 실험하고 작업을 트리거하여 비즈니스 프로세스를 효과적으로 자동화하십시오.

위의 문서는 샘플일 뿐이며 특정 요구 사항 및 대상 고객에 따라 추가로 수정하고 사용자 지정해야 합니다.