---
# System prepended metadata

title: 'Jam 07 - Exercise 5: System Integration'
tags: [polymorphism, "2 \U0001F4DD in writing", inheritance, uml, interfaces, junit, abstract-classes, "3 \U0001F9EA in testing", "4 \U0001F973 done"]

---

---
title: "Jam 07 - Exercise 5: System Integration"
tags: 
  - 2 📝 in writing
  - 3 🧪 in testing
  - 4 🥳 done
  - inheritance
  - interfaces
  - polymorphism
  - uml
  - abstract-classes
  - junit
---
<!-- markdownlint-disable line-length single-h1 no-inline-html -->
<!-- markdownlint-configure-file { "ul-indent": { "indent": 4 }, "link-fragments": {"ignore_case": true} } -->

{%hackmd dJZ5TulxSDKme-3fSY4Lbw %}

# Exercise 5 - System Integration

## Overview - Exercise 5

You've worked incredibly hard implementing interfaces, exceptions, inheritance hierarchies, and state diagrams! 🌟 Now it's time to bring everything together. Rather than having you write all the integration code from scratch, we'll provide you with a well-structured implementation that ties all your components together. Your task is to understand how these pieces work together and why certain design choices were made.

This approach mirrors real-world development, where you often need to:

- Read and understand existing code
- See how different components interact
- Learn from established patterns and practices
- Make informed modifications to complex systems

As you review the code, think about:

- How the Employee hierarchy controls access to Register operations
- How the Searchable interface enables unified search across different types
- How exceptions help maintain system integrity
- How state management ensures proper operation sequencing

Let's dive in and see how all your hard work comes together! 🚀

Note: I'm about 92% certain this implementation *should* work regardless of how you implemented your code.  If you get stuck and something doesn't work, post on Discord!

## Step 1: Add Employee Field to Register

First, let's add the `currentUser` field to the Register class:

```java
public class Register {
    // ... existing fields ...
    private Employee currentUser;  // Add this field

    // ... existing methods ...
}
```

## Step 2: Add Login/Logout Methods

Add these methods to the Register class:

```java
public class Register {
    // ... existing code ...

    public boolean login(Employee employee) {
        if (currentUser != null) {
            return false;  // Already logged in
        }
        currentUser = employee;
        return true;
    }

    public boolean logout() {
        if (currentUser == null) {
            return false;  // Already logged out
        }
        currentUser = null;
        return true;
    }

    public Employee getCurrentUser() {
        return currentUser;
    }
}
```

## Step 3: Add Permission Check Method

Add this method to check if the current user has permission for an operation:

```java
public class Register {
    // ... existing code ...

    private boolean shouldBlockOperation(boolean requiresAdmin) {
        if (currentUser == null) {
            return true;  // No user logged in means operation should be blocked
        }
        if (requiresAdmin) {
            return !currentUser.hasAdminPrivileges();  // Block if user doesn't have admin privileges
        }
        return !currentUser.canAccessRegister();  // Block if user can't access register
    }
}
```

## Step 4: Update Transaction Methods

Now let's update the transaction methods to require login:

```java
public class Register {
    // ... existing code ...

    public boolean startTransaction() {
        if (shouldBlockOperation(false)) {
            return false;
        }
        // ... existing startTransaction code ...
    }

    public boolean addProductToTransaction(String sku) {
        if (shouldBlockOperation(false)) {
            return false;
        }
        // ... existing addProductToTransaction code ...
    }

    public Map<Money, Integer> processPayment(Map<Money, Integer> payment) {
        if (shouldBlockOperation(false)) {
            return null;
        }
        // ... existing processPayment code ...
    }
}
```

## Step 5: Create Integration Test

Create a new test file `RegisterIntegrationTest.java` in the `jam07` test folder:

```java
package jam07;

import static org.junit.jupiter.api.Assertions.*;

import jam05.Product;
import jam05.ProductCatalog;
import jam06.Register;
import java.time.LocalDate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class RegisterIntegrationTest {
    private static int registerCounter = 0;
    
    private Register register;
    private Cashier cashier;
    private Manager manager;
    private Product testProduct;

    @BeforeEach
    void setUp() {
        // Set up catalog and register
        ProductCatalog catalog = new ProductCatalog();
        try {
            testProduct = new Product("Test Product", "TEST123", 9.99);
            catalog.addProduct(testProduct);
        } catch (jam07.InvalidPriceException e) {
            System.err.println("Error creating product: " + e.getMessage());
            System.exit(1);
        }

        String registerName = String.format("TEST-%03d", ++registerCounter);
        register = Register.createRegister(registerName, catalog);
        cashier = new Cashier("C001", "Test Cashier", LocalDate.now());
        manager = new Manager("M001", "Test Manager", LocalDate.now());
    }

    @Test
    void shouldRequireLoginForOperations() {
        // Test operations without login
        assertFalse(register.startTransaction());
        assertFalse(register.addProductToTransaction(testProduct.getSku()));

        // Login as cashier
        assertTrue(register.login(cashier));

        // Test operations with login
        assertTrue(register.startTransaction());
        assertTrue(register.addProductToTransaction(testProduct.getSku()));
    }

    @Test
    void shouldAllowManagerAdminOperations() {
        // Login as manager
        assertTrue(register.login(manager));

        // Test admin operations
        assertTrue(manager.hasAdminPrivileges());
    }

    @Test
    void shouldManageUserLoginAndLogout() {
        // Initially no user should be logged in
        assertNull(register.getCurrentUser());

        // Login as cashier
        assertTrue(register.login(cashier));
        assertEquals(cashier, register.getCurrentUser());

        // Try to log-in again (should fail)
        assertFalse(register.login(manager));
        assertEquals(cashier, register.getCurrentUser());  // Should still be a cashier

        // Logout
        assertTrue(register.logout());
        assertNull(register.getCurrentUser());

        // Try to log-out again (should fail)
        assertFalse(register.logout());
        assertNull(register.getCurrentUser());
    }

    @Test
    void shouldEnforceAdminPrivileges() {
        // Log-in as cashier
        assertTrue(register.login(cashier));
        
        // Cashier should be able to perform regular operations
        assertTrue(register.startTransaction());
        assertTrue(register.addProductToTransaction(testProduct.getSku()));
        
        // Cashier should be able to perform basic searches
        assertTrue(register.matches("TEST-001")); // Can search register name
        assertTrue(register.matches("0")); // Can search drawer balance
        
        // Cashier should not be able to perform admin operations
        assertNull(register.getCompletedTransactions());
        
        // Logout and login as manager
        assertTrue(register.logout());
        assertTrue(register.login(manager));
        
        // Manager should be able to perform both regular and admin operations
        assertTrue(register.voidTransaction());
        assertTrue(register.startTransaction());
        assertTrue(register.addProductToTransaction(testProduct.getSku()));
        
        // Manager should have full search capabilities
        assertTrue(register.matches("TEST-001")); // Can search register name
        assertTrue(register.matches("0")); // Can search drawer balance
        assertFalse(register.searchTransactions("IN_PROGRESS")
                .isEmpty()); // Can search transactions
        
        // Manager should be able to perform admin operations
        assertNotNull(register.getCompletedTransactions());
    }
}
```

## Step 6: Run and Verify Tests

1. Run the tests to verify your implementation:

   ```bash
   # Right click on the test folder in IntelliJ
   # Click "Run Tests in 'csci205_jams'"
   ```

2. Fix any failing tests by:
   - Checking error messages
   - Verifying method implementations
   - Ensuring proper permission checks
   - Testing edge cases

## Save Your Work - Exercise 5

**Run all tests to verify your implementation**:

```bash
# Right click on the test folder in IntelliJ
# Click "Run Tests in 'csci205_jams'"
# Ensure all tests pass
```

**Stage your changes**:

```bash
git add src/main/java/jam06/Register.java src/test/java/jam07/EmployeeTest.java src/test/java/jam07/ProductCatalogTest.java src/test/java/jam07/ProductTest.java src/test/java/jam07/RegisterIntegrationTest.java src/test/java/jam07/RegisterTest.java src/test/java/jam07/TransactionTest.java
```

**Verify what files are uncommitted**:

```bash
git status
```

**Commit your work**:

```bash
git commit -m "jam07: Add employee authentication to Register"
```

:::success
🔑 **Key Takeaways**

- Components must work together seamlessly
- Integration testing is crucial
- Error handling must be comprehensive
- State management is critical
- Documentation ensures maintainability
- Testing verifies system behavior

:::

Remember: Every great developer started exactly where you did. Keep building, keep learning, and most importantly - be proud of how far you've come! 🌟
