ActionResult Architecture
Table of Contentsβ
- Overview
- Architecture Evolution
- Core Components
- Support Components
- Design Patterns
- Integration Points
- Performance Characteristics
- Extension Points
- Migration Guide
- Testing Strategy
- Security Considerations
- Future Enhancements
- Best Practices
- Component Reference
Overviewβ
ActionResult serves as the universal return type for all actions in the Brobot framework, encapsulating comprehensive information generated during action execution. Version 2.0 introduces a component-based architecture that transforms the original monolithic design into a well-structured system of focused, single-responsibility components.
Related Documentation: ActionResult Components Quick Reference | Upgrading to Latest | ActionConfig Overview
Architecture Evolutionβ
Legacy Architectureβ
The original ActionResult was a monolithic design handling 30+ responsibilities:
- Match collection management
- Text extraction and aggregation
- Timing and duration tracking
- Scene analysis data
- Region definitions
- Movement tracking
- Execution history
- State management
- Logging and metrics
- Sorting and filtering operations
- Statistical calculations
- Serialization concerns
Component-Based Architecture (v2.0)β
The refactored architecture delegates responsibilities to specialized components while maintaining complete backward compatibility through a facade pattern.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ActionResult β
β (Facade) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Core Fields: β
β - actionDescription: String β
β - success: boolean β
β - actionConfig: ActionConfig (see ActionConfig Overview) β
β - outputText: String β
βββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββ€
β Component Delegates (9 specialized components): β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β MatchCollection β β TimingData β β
β β - matches β β - startTime β β
β β - sorting β β - endTime β β
β β - filtering β β - duration β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β βTextExtractionResultβ β StateTracker β β
β β - accumulated β β - activeStates β β
β β - selected β β - stateMatches β β
β β - matchText β β - activations β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β RegionManager β β MovementTracker β β
β β - definedRegions β β - movements β β
β β - namedRegions β β - distances β β
β β - unions β β - paths β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β ActionAnalysis β βExecutionHistory β β
β β - sceneAnalyses β β - records β β
β β - masks β β - lifecycle β β
β β - customAnalysis β β - timeline β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β ββββββββββββββββββββ β
β β ActionMetrics β Performance & efficiency tracking β
β β - executionTimes β β
β β - phaseMetrics β β
β β - efficiencyScore β β
β ββββββββββββββββββββ β
βββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββββ
Core Componentsβ
Note: Code examples in this document show class structures and method signatures for architectural understanding. For complete implementations, see the
io.github.jspinak.brobot.action.resultpackage in the Brobot source code.
1. MatchCollectionβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Manages all match-related operations
public class MatchCollection {
private List<Match> matches; // Current matches after filtering/sorting
private List<Match> initialMatches; // Original unmodified matches for history
private int maxMatches; // Limit to prevent memory issues
// Key operations
public void add(Match... matches); // Add matches with automatic max enforcement
public void sort(SortStrategy strategy); // Sort by score, size, or distance
public Optional<Match> getBest(); // Get highest-scoring match
public MatchCollection filter(Predicate<Match> predicate); // Filter with custom logic
public MatchStatistics getStatistics(); // Delegate to statistics component
}
Features:
- Multiple sorting strategies (score, size, distance)
- Flexible filtering with predicates
- Statistical analysis delegation
- Set operations (minus, intersection)
- Automatic max match enforcement
2. TimingDataβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Handles all timing and duration tracking
public class TimingData {
private LocalDateTime startTime; // Timestamp when action started
private LocalDateTime endTime; // Timestamp when action completed
private Duration totalDuration; // Calculated total duration
private List<TimeSegment> segments; // Phase-level timing breakdown
// Key operations
public void start(); // Mark action start, record timestamp
public void stop(); // Mark action end, calculate duration
public Duration getElapsed(); // Get time elapsed since start
public void addSegment(String name, Duration duration); // Track phase timing
}
Features:
- Automatic timing calculation
- Phase timing support
- Overhead calculation
- Human-readable formatting
3. TextExtractionResultβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Manages text extraction and OCR results
public class TextExtractionResult {
private Text accumulatedText;
private String selectedText;
private Map<Match, String> matchTextMap;
// Key operations
public void addText(String text);
public void addMatchText(Match match, String text);
public String getCombinedText();
}
Features:
- Accumulated text tracking
- Match-specific text mapping
- Selected text management
- Multiple text source merging
4. StateTrackerβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Tracks state information during execution
public class StateTracker {
private Set<String> activeStates; // Currently active states
private Map<String, List<Match>> stateMatches; // Matches grouped by state
private Map<String, Integer> stateActivationCounts; // Frequency tracking
// Key operations
public void recordActiveState(String stateName); // Mark state as active
public void recordStateMatch(String stateName, Match match); // Associate match with state
public Optional<String> getMostActiveState(); // Get most frequent state
}
Features:
- Active state detection
- State-match associations
- Activation frequency tracking
- State activity analysis
5. RegionManagerβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Manages region definitions and operations
public class RegionManager {
private List<Region> definedRegions;
private Map<String, Region> namedRegions;
// Key operations
public void defineRegion(Region region);
public void defineNamedRegion(String name, Region region);
public Optional<Region> getUnion();
public Optional<Region> getIntersection();
}
Features:
- Anonymous and named regions
- Union/intersection calculations
- Area-based sorting
- Primary region access
6. MovementTrackerβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Tracks drag and movement operations
public class MovementTracker {
private List<Movement> movements;
// Key operations
public void recordMovement(Movement movement);
public double getTotalDistance();
public boolean isClosedPath(double tolerance);
public Optional<Region> getBoundingBox();
}
Features:
- Movement sequence tracking
- Distance calculations
- Path analysis (closed/open)
- Bounding box computation
7. ActionAnalysisβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Manages analysis data and results
public class ActionAnalysis {
private SceneAnalyses sceneAnalyses;
private Mat mask;
private Map<String, Object> customAnalysis;
// Key operations
public void addSceneAnalysis(SceneAnalysis analysis);
public void addCustomAnalysis(String key, Object data);
public <T> Optional<T> getCustomAnalysis(String key, Class<T> type);
}
Features:
- Scene analysis aggregation
- Binary mask management
- Custom analysis storage
- Type-safe retrieval
8. ExecutionHistoryβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Tracks action execution history
public class ExecutionHistory {
private List<ActionRecord> records;
private ActionLifecycle lifecycle;
// Key operations
public void recordStep(ActionRecord record);
public List<ActionRecord> getSuccessfulSteps();
public double getSuccessRate();
public String formatTimeline();
}
Features:
- Step-by-step recording
- Success/failure analysis
- Timeline visualization
- Duration tracking
9. ActionMetricsβ
Package: io.github.jspinak.brobot.action.result
Responsibility: Tracks performance metrics and efficiency scores
public class ActionMetrics {
private List<Duration> executionTimes;
private Map<String, Duration> phaseMetrics;
// Key operations
public void recordExecutionTime(Duration duration);
public void recordPhase(String phaseName, Duration duration);
public double getEfficiencyScore();
public String formatPerformance();
}
Features:
- Execution time tracking
- Phase-level performance metrics
- Efficiency score calculation
- Performance summary formatting
Support Componentsβ
MatchStatisticsβ
Provides statistical analysis of match collections:
- Median region/location calculation
- Score distribution analysis
- Confidence level determination
- Density calculations
- Bounding box computation
MatchFilterβ
Static utility for filtering operations:
- Filter by state object/owner
- Score-based filtering
- Area-based filtering
- Distance-based filtering
- Duplicate removal
ActionResultBuilderβ
Fluent builder for constructing ActionResult instances:
ActionResult result = new ActionResultBuilder()
.withSuccess(true)
.withDescription("Found button")
.withMatches(matchList)
.withTiming(startTime, endTime)
.withActiveState("MainMenu")
.build();
Design Patternsβ
1. Facade Patternβ
ActionResult acts as a facade, providing a simplified interface to the complex subsystem of components while maintaining backward compatibility.
2. Delegation Patternβ
All operations are delegated to specialized components, keeping ActionResult focused on coordination rather than implementation.
3. Builder Patternβ
ActionResultBuilder provides flexible construction with optional parameters and method chaining.
4. Strategy Patternβ
MatchCollection uses strategy pattern for sorting operations with configurable strategies.
5. Repository Patternβ
Components like RegionManager and StateTracker act as repositories for their respective domain objects.
Integration Pointsβ
For complete information on Action classes, see the Action Hierarchy documentation.
Real-World Example: Login Flow Automationβ
Here's a complete example showing how ActionResult components work together in a real automation scenario:
import io.github.jspinak.brobot.action.Action;
import io.github.jspinak.brobot.action.ActionResult;
import io.github.jspinak.brobot.action.ObjectCollection;
import io.github.jspinak.brobot.action.basic.click.ClickOptions;
import io.github.jspinak.brobot.action.basic.find.PatternFindOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Demonstrates ActionResult component usage in a login automation workflow.
* Shows how components track matches, timing, state, and provide detailed results.
*/
@Component
public class LoginAutomation {
@Autowired
private Action action;
public ActionResult performLogin(String username, String password) {
// Use builder for clean construction
ActionResult result = new ActionResultBuilder()
.withDescription("Login workflow execution")
.build();
// Step 1: Find and click username field
PatternFindOptions findOptions = PatternFindOptions.forPreciseSearch();
ActionResult usernameResult = action.find(findOptions, getUsernameField());
if (usernameResult.isSuccess()) {
// Components automatically tracked:
// - MatchCollection: Stores found username field match
// - TimingData: Records find operation duration
// - StateTracker: Records "LoginScreen" as active state
result.add(usernameResult.getMatchList());
action.type(username);
// Step 2: Find and fill password field
ActionResult passwordResult = action.find(findOptions, getPasswordField());
if (passwordResult.isSuccess()) {
result.add(passwordResult.getMatchList());
action.type(password);
// Step 3: Click login button
ClickOptions clickOptions = new ClickOptions.Builder()
.setNumberOfClicks(1)
.build();
ActionResult loginResult = action.click(clickOptions, getLoginButton());
// Aggregate results
result.add(loginResult.getMatchList());
result.setSuccess(true);
// Access component data for analysis
System.out.println("Total matches found: " + result.getMatchCount());
System.out.println("Execution time: " + result.getExecutionTimeMs() + "ms");
System.out.println("Active states: " + result.getActiveStates());
// ExecutionHistory tracks all steps
// TimingData provides breakdown by operation
// StateTracker confirms successful state transitions
} else {
result.setSuccess(false);
System.err.println("Password field not found");
}
} else {
result.setSuccess(false);
System.err.println("Username field not found");
}
return result;
}
private ObjectCollection getUsernameField() { /* ... */ return null; }
private ObjectCollection getPasswordField() { /* ... */ return null; }
private ObjectCollection getLoginButton() { /* ... */ return null; }
}
What This Example Demonstrates:
- ActionResultBuilder: Clean construction with fluent API
- MatchCollection: Aggregates matches from multiple find operations
- TimingData: Automatically tracks total execution time
- StateTracker: Monitors state transitions (LoginScreen β LoggedIn)
- ExecutionHistory: Records each step for debugging
- Component Facade: Simple API hides component complexity
With Action Classesβ
public class Click {
public ActionResult execute(ObjectCollection objects) {
ActionResult result = new ActionResult(clickOptions);
// Populate result using components
result.add(foundMatch);
result.setSuccess(true);
return result;
}
}
With Logging Systemβ
// Components provide formatted output
String matchSummary = result.getMatchCollection().getStatistics().format();
String timingSummary = result.getTimingData().format();
String stateSummary = result.getStateTracker().format();
With Testing Frameworkβ
For comprehensive testing guidance, see Testing Overview and Testing Strategy.
// Fine-grained assertions on components
assertThat(result.getMatchCount()).isEqualTo(3);
assertThat(result.getExecutionTimeMs()).isLessThan(1000);
assertThat(result.getActiveStates()).contains("LoginScreen");
Performance Characteristicsβ
Memory Efficiencyβ
- Eager Initialization: Components initialized at construction for consistent state
- Shared References: No unnecessary copying
- Bounded Collections: MaxMatches enforcement
Computational Efficiencyβ
- O(1) Access: Direct component access
- O(n log n) Sorting: Efficient match sorting
- O(n) Filtering: Linear filtering operations
- Cached Statistics: Statistics calculated once
Garbage Collectionβ
- Reduced Object Graph: Smaller, focused objects
- Clear Ownership: Components own their data
- Explicit Cleanup: Clear() methods on components
Extension Pointsβ
Custom Analysis Typesβ
// Add custom analysis data
result.getActionAnalysis().addCustomAnalysis("colorProfile", colorData);
// Retrieve with type safety
Optional<ColorProfile> profile = result.getActionAnalysis()
.getCustomAnalysis("colorProfile", ColorProfile.class);
Custom Sorting Strategiesβ
// Extend MatchCollection.SortStrategy
matchCollection.sort(SortStrategy.CUSTOM_RELEVANCE);
Custom Statisticsβ
// Extend MatchStatistics for domain-specific metrics
public class GameMatchStatistics extends MatchStatistics {
public double getAverageHealthBarFullness() { ... }
}
Migration Guideβ
For complete migration details and examples, see the Upgrading to Latest guide.
For API Consumersβ
No changes required! The facade maintains complete backward compatibility:
// Old code continues to work
ActionResult result = action.execute();
result.add(match);
result.sortMatchObjects();
List<Match> matches = result.getMatchList();
For Action Implementersβ
Use the builder for cleaner construction:
// Old way
ActionResult result = new ActionResult();
result.setSuccess(true);
result.add(matches);
result.setDuration(duration);
// New way (optional)
ActionResult result = ActionResultBuilder.successWith(matches)
.withTiming(startTime, endTime)
.build();
For Framework Extendersβ
Components are accessed through the facade's public API methods:
// Access component data through facade methods
List<Match> matches = result.getMatchList();
long executionTime = result.getExecutionTimeMs();
Set<String> activeStates = result.getActiveStates();
MatchStatistics stats = result.getMatchStatistics();
double confidence = stats.getConfidence();
Testing Strategyβ
Component Unit Testingβ
Each component has focused unit tests:
@Test
void testMatchCollectionSorting() {
MatchCollection collection = new MatchCollection();
collection.add(match1, match2, match3);
collection.sortByScoreDescending();
assertThat(collection.getBest()).contains(match3);
}
Integration Testingβ
Test component interactions:
@Test
void testActionResultDelegation() {
ActionResult result = new ActionResult();
result.add(match);
// Verify delegation
assertThat(result.getMatchCollection().contains(match)).isTrue();
assertThat(result.getStateTracker().getActiveStates()).contains(stateName);
}
Performance Testingβ
Verify performance characteristics:
@Benchmark
public void benchmarkMatchSorting() {
result.sortMatchObjectsDescending();
}
Security Considerationsβ
Input Validationβ
- Components validate input parameters
- Null-safe operations throughout
- Bounded collection sizes
Data Isolationβ
- Components encapsulate their data
- No shared mutable state
- Defensive copying where needed
Serialization Safetyβ
- @JsonIgnore on non-serializable fields
- Clean separation of transient data
- Controlled exposure of internal state
Future Enhancementsβ
Planned Improvementsβ
- Async Support: Concurrent component operations
- Streaming API: Process large result sets efficiently
- Event System: Observable result changes
- Metrics Dashboard: Real-time performance visualization
- Plugin Architecture: Dynamic component registration
Potential Optimizationsβ
- Object Pooling: Reuse component instances
- Lazy Loading: Defer expensive calculations
- Caching Layer: Cache computed statistics
- Compression: Compress large match collections
Best Practicesβ
Do'sβ
- β Use components for focused operations
- β Leverage builder for complex construction
- β Access statistics for analysis
- β Clear components when done
- β Use appropriate sorting strategies
Don'tsβ
- β Don't access component internals directly
- β Don't modify collections while iterating
- β Don't ignore null checks
- β Don't bypass the facade for basic operations
- β Don't store references to internal collections
Component Referenceβ
| Component | Lines | Responsibility | Key Methods |
|---|---|---|---|
| MatchCollection | 369 | Match management | add(), sort(), filter(), getBest() |
| TimingData | 231 | Timing tracking | start(), stop(), getElapsed() |
| MatchStatistics | 294 | Statistical analysis | getMedian(), getConfidence() |
| TextExtractionResult | 219 | Text management | addText(), getCombinedText() |
| StateTracker | 230 | State tracking | recordActiveState(), getMostActiveState() |
| RegionManager | 266 | Region management | defineRegion(), getUnion() |
| MovementTracker | 265 | Movement tracking | recordMovement(), getTotalDistance() |
| ActionAnalysis | 230 | Analysis data | addSceneAnalysis(), addCustomAnalysis() |
| ActionMetrics | 302 | Performance metrics | recordExecutionTime(), getEfficiencyScore() |
| ExecutionHistory | 291 | Execution tracking | recordStep(), getSuccessRate() |
| MatchFilter | 332 | Filtering utilities | byMinScore(), nearLocation() |
| ActionResultBuilder | 424 | Result construction | withMatches(), build() |
Conclusionβ
The refactored ActionResult architecture transforms a monolithic class into a well-structured system of focused components. This design provides:
- Better Maintainability: Each component has a single, clear responsibility
- Enhanced Testability: Smaller units are easier to test in isolation
- Improved Extensibility: New features can be added to specific components
- Backward Compatibility: Existing code continues to work unchanged
- Performance Benefits: Lazy initialization and focused operations
The component-based architecture positions ActionResult for future growth while maintaining the stability and reliability expected by existing consumers.