Cvičenie 6
Code Smells, Unit Testy, úvod do MVC
Cvičenie 6
Úlohy
- Pracujte ďalej na projekte konzultujte s cvičiacim
Java Úlohy
Research Archive: Serialization and Parallel Processing
Data persistence, checked exceptions, and thread-based task execution
In this task you will build a small research archive system for a university lab. The lab records experiment measurements, stores them on disk, loads them back later, and runs analyses in parallel to speed up processing.
Learning goals
By completing this task, you will practice:
- Designing classes with clear responsibilities
- Implementing custom checked exceptions
- Using Java serialization to persist and restore object graphs
- Using defensive copying and immutable views for safer APIs
- Executing independent tasks in parallel using threads
- Handling partial completion and timeout-like behavior robustly
Domain story
A university research lab collects measurement sets for many small experiments. Each experiment has metadata and measurement values. The lab wants to:
- Store experiment records in memory
- Save all records to disk and restore them later
- Run computational tasks in parallel over records
Your implementation should be reusable and testable - not a one-off script.
What to implement
All classes must be in package org.jikvict.tasks.exposed.
1) InvalidRecordException
Create a checked exception:
- Class name:
InvalidRecordException - Extends:
Exception - Constructor:
InvalidRecordException(String message)
Use this when record data is invalid.
2) DuplicateRecordException
Create a checked exception:
- Class name:
DuplicateRecordException - Extends:
Exception - Constructor:
DuplicateRecordException(String message)
Use this when adding a record with an already existing id.
3) ExperimentRecord
Represents one lab record and must support serialization.
Required class properties:
- Class name:
ExperimentRecord - Must implement
java.io.Serializable - Constructor:
ExperimentRecord(String recordId, String author, java.util.List<Integer> measurements, long createdAtEpochMilli)- Throws
InvalidRecordExceptionon invalid input
Required behavior:
recordIdandauthormust be non-null and not blankmeasurementsmust be non-null, non-empty, and contain only non-negative valuescreatedAtEpochMillimust be positive- Store measurements defensively (avoid exposing internal mutable state)
- Methods:
String getRecordId()String getAuthor()java.util.List<Integer> getMeasurements()(unmodifiable view)long getCreatedAtEpochMilli()double average()void addMeasurement(int value)throwsInvalidRecordException
Advanced serialization requirement:
- Add a transient cache field named
cachedAverageof typedouble - Recompute cache after deserialization (for example in
readObject)
4) ExperimentArchive
Container for many records with save/load support.
Required class properties:
- Class name:
ExperimentArchive - Constructor: no-arg public constructor
Required behavior:
void addRecord(ExperimentRecord record)throwsDuplicateRecordException- duplicate means same
recordId
- duplicate means same
java.util.List<ExperimentRecord> getRecords()- return an unmodifiable list
java.util.Optional<ExperimentRecord> findById(String recordId)void saveToFile(String filePath)throwsjava.io.IOException- serialize entire archive to file
static ExperimentArchive loadFromFile(String filePath)- throws
java.io.IOException,ClassNotFoundException
- throws
5) ParallelTaskRunner
Utility that executes independent tasks using a fixed-size thread pool.
Required class properties:
- Class name:
ParallelTaskRunner - Constructor:
ParallelTaskRunner(int threadCount)- threadCount must be positive
Required behavior:
java.util.List<?> runAll(java.util.List<? extends java.util.concurrent.Callable<?>> tasks)- execute tasks in parallel
- return results in the same order as input task list
- if task list is null, throw
IllegalArgumentException
java.util.List<?> runAllWithTimeout(java.util.List<? extends java.util.concurrent.Callable<?>> tasks, long timeoutMillis)- execute tasks in parallel
- return only results that completed before timeout
- preserve input order among returned results
- timeoutMillis must be positive
void shutdown()- release resources of underlying executor
Design note: handling interruption, cancellation, and checked exceptions cleanly is part of the challenge.
Constraints and expectations
- Do not use external libraries for serialization or concurrency utilities beyond standard Java SDK.
- Avoid leaking mutable internal collections.
- Avoid race conditions and resource leaks.
Suggested implementation strategy
- Implement both exceptions first.
- Implement
ExperimentRecordwith full validation and defensive copying. - Implement
ExperimentArchive, then test save/load manually. - Implement
ParallelTaskRunnerand verify execution ordering. - Add timeout handling and proper shutdown behavior.