Persistence Module Architecture
Overviewโ
The Brobot Persistence Module provides a flexible, pluggable architecture for recording and persisting action execution data during automation runs. This module enables:
- Recording of action executions for debugging and analysis
- Multiple persistence backends (file, database, in-memory)
- Session management and replay capabilities
- Export/import of action histories
- Integration with both Java projects and the JavaFX runner
For usage instructions, see the Persistence User Guide.
Architecture Designโ
Three-Module Architectureโ
brobot-parent/
โโโ brobot-library/ # Core automation (no persistence)
โโโ brobot-persistence/ # Optional persistence module
โโโ brobot-runner/ # JavaFX UI application
Key Design Principlesโ
- Separation of Concerns: The library remains pure automation functionality
- Optional Integration: Projects can choose whether to include persistence
- Pluggable Backends: Different storage mechanisms without code changes
- Zero Dependencies: File-based persistence requires no database
- Spring Integration: Seamless integration with Spring Boot applications
Module Structureโ
Core Componentsโ
brobot-persistence/
โโโ config/
โ โโโ PersistenceConfiguration.java # Configuration model
โโโ provider/
โ โโโ AbstractPersistenceProvider.java # Base implementation
โ โโโ FileBasedPersistenceProvider.java
โ โโโ InMemoryPersistenceProvider.java
โ โโโ DatabasePersistenceProvider.java
โโโ database/
โ โโโ entity/ # JPA entities
โ โโโ repository/ # Spring Data repositories
โโโ spring/
โ โโโ PersistenceAutoConfiguration.java
โ โโโ PersistenceEventListener.java
โโโ PersistenceProviderFactory.java # Factory for creating providers
Interface Designโ
The PersistenceProvider interface in the library module defines the contract:
public interface PersistenceProvider {
// Session management
String startSession(String sessionName, String application, String metadata);
String stopSession();
void pauseRecording();
void resumeRecording();
boolean isRecording();
// Recording
void recordAction(ActionRecord record, StateObject stateObject); // StateObject: see States guide
void recordBatch(List<ActionRecord> records);
// Export/Import
ActionHistory exportSession(String sessionId); // Returns ActionHistory for replay/analysis
String importSession(ActionHistory history, String sessionName);
// Query
List<String> getAllSessions();
SessionMetadata getSessionMetadata(String sessionId); // SessionMetadata is a nested class
void deleteSession(String sessionId);
/**
* Metadata about a recording session.
* Defined as PersistenceProvider.SessionMetadata in the actual implementation.
*/
class SessionMetadata {
// Session details
}
}
Persistence Backendsโ
1. File-Based Persistenceโ
Use Case: Projects that need persistence without database dependencies
Features:
- JSON and CSV format support (XML planned but not yet implemented)
- Optional compression (GZIP)
- Organized directory structure
- Automatic file rotation
- No external dependencies
Storage Structure:
brobot-history/
โโโ sessions/
โโโ 20250807_143022_MySession/
โโโ metadata.json
โโโ records_20250807_143022.json
โโโ records_20250807_144512.json.gz
2. Database Persistenceโ
Use Case: Enterprise applications requiring robust querying and analysis
Features:
- JPA/Hibernate integration
- Support for any JPA-compatible database
- Rich querying capabilities
- Transaction support
- Relationship management
Entities:
RecordingSessionEntity: Session metadataActionRecordEntity: Individual action recordsMatchEntity: Match results from find operations
3. In-Memory Persistenceโ
Use Case: Testing and temporary sessions
Features:
- Zero configuration
- Fast performance
- Session limits to prevent memory issues
- Optional persistence on shutdown
- Memory statistics
Configurationโ
Configuration Optionsโ
brobot:
persistence:
enabled: true
type: FILE # FILE, DATABASE, MEMORY
file:
base-path: ./brobot-history
format: JSON # JSON, CSV
compress-exports: false
pretty-print: true
max-file-size-mb: 100
database:
url: jdbc:h2:file:./data/brobot
username: sa
password:
batch-size: 100
memory:
max-sessions: 10
max-records-per-session: 1000
persist-on-shutdown: true
performance:
async-recording: true
buffer-size: 100
flush-interval-seconds: 60
thread-pool-size: 3
Spring Boot Auto-Configurationโ
The module provides auto-configuration for Spring Boot applications:
@SpringBootApplication
@Import(PersistenceAutoConfiguration.class)
public class MyApplication {
// Persistence is automatically configured
}
Usage Patternsโ
1. Java Project with File Persistenceโ
package com.example.automation;
import io.github.jspinak.brobot.persistence.PersistenceProvider;
import io.github.jspinak.brobot.persistence.PersistenceProviderFactory;
import io.github.jspinak.brobot.persistence.config.PersistenceConfiguration;
import io.github.jspinak.brobot.model.action.ActionHistory;
import io.github.jspinak.brobot.model.state.StateImage;
import io.github.jspinak.brobot.action.Action;
public class FilePersistenceExample {
public static void main(String[] args) {
// Create persistence provider
PersistenceConfiguration config = PersistenceConfiguration.fileDefault();
config.getFile().setBasePath("./automation-history");
PersistenceProvider persistence = PersistenceProviderFactory.create(config);
// Start recording
String sessionId = persistence.startSession("TestRun", "MyApp", null);
try {
// Define StateImage for automation
StateImage stateImage = new StateImage.Builder()
.setName("submit-button")
.addPattern("submit.png")
.build();
// Your automation code (Action would be initialized via dependency injection in real apps)
// action.click(stateImage); // Actions are recorded automatically if integrated
// Stop and export
persistence.stopSession();
ActionHistory history = persistence.exportSession(sessionId);
System.out.println("Session completed with " +
history.getTimesSearched() + " actions recorded");
} catch (Exception e) {
persistence.stopSession();
throw e;
}
}
}
2. Spring Boot Applicationโ
package com.example.automation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.github.jspinak.brobot.persistence.PersistenceProvider;
import io.github.jspinak.brobot.action.Action;
import io.github.jspinak.brobot.model.state.StateImage;
import io.github.jspinak.brobot.action.ActionResult;
@Component
public class AutomationService {
@Autowired
private PersistenceProvider persistence;
@Autowired
private Action action;
// Define StateImages for UI elements
private final StateImage loginButton = new StateImage.Builder()
.setName("loginButton")
.addPattern("login-button.png")
.build();
private final StateImage usernameField = new StateImage.Builder()
.setName("usernameField")
.addPattern("username-field.png")
.build();
private final StateImage submitButton = new StateImage.Builder()
.setName("submitButton")
.addPattern("submit-button.png")
.build();
public void runAutomation() {
persistence.startSession("Automated Test", "WebApp", null);
try {
// Automation with automatic recording
ActionResult loginResult = action.click(loginButton);
if (loginResult.isSuccess()) {
action.click(usernameField);
action.type("user");
action.click(submitButton);
}
} finally {
persistence.stopSession();
}
}
}
3. Runner Applicationโ
The runner uses the persistence module internally:
package io.github.jspinak.brobot.runner.persistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.github.jspinak.brobot.persistence.PersistenceProvider;
@Service
public class PersistenceAdapterService {
@Autowired
private PersistenceProvider persistenceProvider;
// UI update callback for JavaFX runner (implementation-specific)
private Runnable uiUpdateCallback;
public void setUiUpdateCallback(Runnable callback) {
this.uiUpdateCallback = callback;
}
public void startRecording(String name, String app) {
persistenceProvider.startSession(name, app, null);
updateUI(); // Runner-specific UI updates
}
public void stopRecording() {
persistenceProvider.stopSession();
updateUI();
}
public boolean isRecording() {
return persistenceProvider.isRecording();
}
/**
* Updates runner UI to reflect current recording state.
* Calls JavaFX UI update callback if configured.
*/
private void updateUI() {
if (uiUpdateCallback != null) {
uiUpdateCallback.run();
}
}
}
Performance Considerationsโ
Asynchronous Recordingโ
- Actions are queued and persisted in background threads
- Configurable buffer sizes and flush intervals
- Automatic fallback to synchronous on queue overflow
Memory Managementโ
- Configurable limits for in-memory storage
- Automatic session eviction (LRU)
- File rotation for large sessions