Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/efrain-svg/Potes_Freddy_ProgInterfacesG_U3/llms.txt

Use this file to discover all available pages before exploring further.

Contact Management App uses Java’s concurrency tools to ensure the user interface stays responsive during heavy operations like loading contacts, searching large lists, and exporting files. All background work runs off the Swing Event Dispatch Thread (EDT) and safely marshals results back to the UI using SwingUtilities.invokeLater().

Background operations overview

OperationMechanismEDT-safe update
Loading contacts on startupSwingWorkerdone()refrescarTabla()
Real-time search/filterSwingWorker with cancellationinvokeLater()sorter.setRowFilter()
Duplicate validationSwingWorkerinvokeLater() → dialog or save
CSV exportExecutorService (2-thread pool)invokeLater() → dialog + re-enable buttons
Status notificationsExecutorService (1-thread pool)invokeLater()lbl_estado.setText()
Every keystroke in the search field triggers solicitarBusquedaAsync(). This method:
  1. Increments an AtomicInteger sequence counter (searchSeq)
  2. Cancels any running searchWorker via cancel(true)
  3. Creates a new SwingWorker that builds a RowFilter in the background
  4. In done(), checks if the sequence number still matches — if not (user typed again), the result is discarded
logica_ventana.java
private void solicitarBusquedaAsync() {
    final int seq = searchSeq.incrementAndGet();
    if (searchWorker != null && !searchWorker.isDone()) {
        searchWorker.cancel(true);
    }
    searchWorker = new SwingWorker<RowFilter<Object, Object>, Void>() {
        @Override
        protected RowFilter<Object, Object> doInBackground() {
            // builds combined text + category filter off the EDT
            return null; // ... combined RowFilter or null for no filter
        }
        @Override
        protected void done() {
            if (isCancelled() || seq != searchSeq.get()) return;
            final RowFilter<Object, Object> filtroFinal;
            try { filtroFinal = get(); } catch (Exception ex) { return; }
            SwingUtilities.invokeLater(new Runnable() {
                @Override public void run() { sorter.setRowFilter(filtroFinal); }
            });
        }
    };
    searchWorker.execute();
}

Duplicate validation

When you save or update a contact, the app validates for duplicates asynchronously:
  1. The UI enters a “busy” state — all buttons and inputs are disabled
  2. A SwingWorker scans the contacts list for matching email or phone
  3. On completion, the EDT is notified — either the save proceeds or an error dialog appears
  4. The UI returns to normal state

Shared state synchronization

Three synchronization mechanisms protect shared mutable state:
A plain Object used as a monitor. Any code that reads or modifies the contactos ArrayList must be wrapped in synchronized (contactosLock) { ... }. This includes adding, updating, removing, and iterating contacts.
A plain Object monitor wrapping the dao.exportarCsv() call. Since exports run in a thread pool, this lock ensures two concurrent exports cannot corrupt the same output file.
A ReentrantLock that is tryLock()-ed before any edit operation begins. If the lock is already held by another operation, the user sees a “Contact is being edited” message. The lock is released after the edit completes or is cancelled.

UI busy state

An AtomicInteger busyCount tracks the number of in-flight operations. When it is greater than zero:
  • All action buttons (New, Update, Delete, Export CSV) are disabled
  • All input fields (name, phone, email, category, search) are disabled
  • The progress bar switches to indeterminate mode
When busyCount drops back to zero, all controls are re-enabled in a single invokeLater() call.
All UI mutations — including re-enabling controls — happen exclusively on the EDT via SwingUtilities.invokeLater(). Background threads never touch Swing components directly.

Build docs developers (and LLMs) love