Input/Output usage
Input/Output usage
What is Input/Output data?
Input and Output objects are necessary to transfer data to the process tasks and get the result. Most often, they are used to transfer data identifiers for processing, data transfer between steps (usually, the data is stored in the database, and only the keys are sent to the next step), and to get the output data - the results of work. It can be business data or information about successful execution.
Input/Output objects structure
You can save any serializable object as an input or output object. Input/output objects store data in the variable HashMap<String, String> variables. The key is the variable name, and the value is the data stored in json format. When reading/saving data in input/output, the added object is automatically serialized/deserialized into json string.
Usage
To upload data to the process input, go to Automation Process Details -> Input Data and upload a data file in json format.
After that, to use the data uploaded through the control server or created in the code, you need to declare a variable with the @Input annotation and the corresponding name and type.
public class SampleTask extends ApTask { @Input(key = "newKey") private String myInputString; @Input private MyTransferClass myTransferObject; ...
In the example above, we expect 2 variables as the input.
The first variable is of the String type. @Input(key = "newKey") means that the variable was passed to the process with the newKey key.
The second variable of MyTransferClass type was passed with myTransferObject key without any additional options. So we just declare the variable with the corresponding type and name, specify the @Input annotation and then we can use the data.
To send data to the output, the @Output annotation is used when declaring a variable. If you want to get the data, make changes and pass it on, you can use both annotations at the same time.
public class SampleTask extends ApTask { @Output @Input private MyTransferClass myTransferObject; @Output private String myOutputString; ...
In this example we get the input object myTransferObject and pass it to the output. We also create an additional variable myOutputString which is also passed to the next steps.
Example
In this example, we work with the Book class. The example consists of two steps. In the first step, we receive the data and pass it to the second step. The second step takes the data from the first step, makes changes and sends it to the output.
Class Book is the entity we'll save in the DataStore and then pass between steps.
import eu.ibagroup.easyrpa.persistence.annotations.Column; import eu.ibagroup.easyrpa.persistence.annotations.Entity; import eu.ibagroup.easyrpa.persistence.annotations.Id; import lombok.Data; import lombok.NoArgsConstructor; @Entity(value = "io_example_books") @NoArgsConstructor @Data public class Book { @Id @Column("index") private String index; @Column("name") private String name; @Column("author") private String author; @Column("count") private String count; public Book(String index, String name, String author) { this.index = index; this.name = name; this.author = author; } public Book(String index, String name, String author, String count) { this.index = index; this.name = name; this.author = author; this.count = count; } }
Transferring the entire object may require a lot of resources. Therefore, the right approach is to save objects in the DataStore and transfer their identifiers between the steps.
For information transfer, a special DTO object is created which contains the process identifier and the transferred data - the entity identifiers in the DataStore.
import lombok.Getter; import lombok.ToString; import java.util.ArrayList; import java.util.List; @ToString public class BooksResultDto { @Getter private final String uuid; @Getter private final List<String> bookIds; public BooksResultDto(String uuid) { this.bookIds = new ArrayList<>(); this.uuid = uuid; } public void add(String id) { bookIds.add(id); } }
In this example, there are enough methods available by default for working with DataStore, so the BookRepository interface remains empty.
import eu.ibagroup.easyrpa.io.entities.Book; import eu.ibagroup.easyrpa.persistence.CrudRepository; import java.util.ArrayList; import java.util.List; public interface BookRepository extends CrudRepository<Book, String> { }
SampleTaskOne receives the books, saves them in the DataStore and passes the DTO object with identifiers to the next step.
import eu.ibagroup.easyrpa.engine.annotation.ApTaskEntry; import eu.ibagroup.easyrpa.engine.annotation.Output; import eu.ibagroup.easyrpa.engine.apflow.ApTask; import eu.ibagroup.easyrpa.io.BookRepository; import eu.ibagroup.easyrpa.io.BooksResultDto; import eu.ibagroup.easyrpa.io.entities.Book; import lombok.extern.slf4j.Slf4j; import javax.inject.Inject; import java.util.Arrays; import java.util.List; import java.util.UUID; @ApTaskEntry(name = "Sample Task One") @Slf4j public class SampleTaskOne extends ApTask { //key to output identification public static final String BOOK_KEY = "Book"; @Output(key = BOOK_KEY) private BooksResultDto booksResult; @Inject private BookRepository bookRepository; @Override public void execute() { booksResult = new BooksResultDto(getUuid()); for (Book book : getBooks()){ //save to DataStore bookRepository.save(book); //add ID to output booksResult.add(book.getIndex()); } } //Getting books. Data can be obtained from the client program, database, scraped from the website, etc. private List<Book> getBooks() { Book thinkingInJava = new Book(UUID.randomUUID().toString(), "Thinking in Java", "Bruce Eckel"); Book cipollino = new Book(UUID.randomUUID().toString(), "Le avventure di Cipollino", "Giovanni Francesco Rodari"); Book warAndPeace = new Book(UUID.randomUUID().toString(), "War and Peace", "Lev Tolstoy"); return Arrays.asList(thinkingInJava, cipollino, warAndPeace); } }
SampleTaskTwo receives the input data from SampleTaskOne using the @Input annotation.
Then, using identifiers from the input DTO object, the data is extracted from the DataStore. After performing manipulations with the obtained data, it is updated in the DataStore, identifiers of new entities are added to the output-object
The annotation @Output indicates that after processing the data will be transferred to the next step.
import eu.ibagroup.easyrpa.engine.annotation.ApTaskEntry; import eu.ibagroup.easyrpa.engine.annotation.Input; import eu.ibagroup.easyrpa.engine.annotation.Output; import eu.ibagroup.easyrpa.engine.apflow.ApTask; import eu.ibagroup.easyrpa.io.BookRepository; import eu.ibagroup.easyrpa.io.BooksResultDto; import eu.ibagroup.easyrpa.io.entities.Book; import lombok.extern.slf4j.Slf4j; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.UUID; import static eu.ibagroup.easyrpa.io.task.SampleTaskOne.BOOK_KEY; @ApTaskEntry(name = "Sample Task Two") @Slf4j public class SampleTaskTwo extends ApTask { @Input(key = BOOK_KEY) @Output private BooksResultDto booksResult; @Inject private BookRepository bookRepository; @Override public void execute() { //get entities List<Book> books = new ArrayList<>(); for (String id : booksResult.getBookIds()) { books.add(bookRepository.findById(id)); } //update entities for (Book book : books) { book.setCount(String.valueOf(getBooksCount(book.getName()))); bookRepository.save(book); } //add new entities to repository Book newBook = getNewBook(); bookRepository.save(newBook); //add new entities to result booksResult.add(newBook.getIndex()); } private Book getNewBook() { return new Book(UUID.randomUUID().toString(), "The Godfather", "Mario Puzo", "50"); } //Getting additional information. Data can be obtained from the client program, database, scraped from the website, etc. private int getBooksCount(String name) { return new Random().nextInt(100); } }
The automation process to run tasks: