Skip to content

Commit 07bc4b9

Browse files
CopilotbedaHovorka
andcommitted
Add Severity enum, EditorException, and require* utility functions
- Created Severity enum with FATAL, ERROR, WARN levels - Created EditorException for editor operations and validation errors - Updated SimulationException to support Severity levels - Added require* utility functions to replace assert() boilerplate - Functions include: requireSimulation, requireEditor, requireValidArgument, requireValidState Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>
1 parent 3ab77ec commit 07bc4b9

4 files changed

Lines changed: 314 additions & 20 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* Brno University of Technology
2+
* Faculty of Information Technology
3+
*
4+
* BSc Thesis 2006/2007
5+
*
6+
* Railway Interlocking Simulator
7+
*
8+
* Bedrich Hovorka
9+
*/
10+
package cz.vutbr.fit.interlockSim.exceptions
11+
12+
/**
13+
* Exception thrown during editor operations, validation, or user mistakes.
14+
* Examples: wrong move, bad element placing, invalid configuration.
15+
*
16+
* @property severity Severity level of the exception
17+
* @property obj Optional object associated with the exception
18+
*/
19+
class EditorException : Exception {
20+
val severity: Severity
21+
private val obj: Any?
22+
23+
/**
24+
* Create EditorException with default FATAL severity
25+
*/
26+
constructor() : this(Severity.FATAL, null as Any?)
27+
28+
/**
29+
* Create EditorException with default FATAL severity
30+
* @param obj Object associated with the exception
31+
*/
32+
constructor(obj: Any?) : this(Severity.FATAL, "", obj)
33+
34+
/**
35+
* Create EditorException with default FATAL severity
36+
* @param message Error message
37+
*/
38+
constructor(message: String) : this(Severity.FATAL, message, null as Any?)
39+
40+
/**
41+
* Create EditorException with specified severity
42+
* @param severity Severity level
43+
* @param message Error message
44+
*/
45+
constructor(severity: Severity, message: String) : this(severity, message, null as Any?)
46+
47+
/**
48+
* Create EditorException with specified severity and object
49+
* @param severity Severity level
50+
* @param message Error message
51+
* @param obj Object associated with the exception
52+
*/
53+
constructor(severity: Severity, message: String, obj: Any?) : super(message) {
54+
this.severity = severity
55+
this.obj = obj
56+
}
57+
58+
/**
59+
* Create EditorException with default FATAL severity and cause
60+
* @param cause Underlying cause
61+
*/
62+
constructor(cause: Throwable?) : this(Severity.FATAL, cause, null as Any?)
63+
64+
/**
65+
* Create EditorException with specified severity and cause
66+
* @param severity Severity level
67+
* @param cause Underlying cause
68+
* @param obj Object associated with the exception
69+
*/
70+
constructor(severity: Severity, cause: Throwable?, obj: Any?) : this(severity, "", cause, obj)
71+
72+
/**
73+
* Create EditorException with all parameters
74+
* @param severity Severity level
75+
* @param message Error message
76+
* @param cause Underlying cause
77+
* @param obj Object associated with the exception
78+
*/
79+
constructor(severity: Severity, message: String, cause: Throwable?, obj: Any?) : super(message, cause) {
80+
this.severity = severity
81+
this.obj = obj
82+
}
83+
84+
/**
85+
* @return object getter
86+
*/
87+
fun getObject(): Any? = obj
88+
89+
override fun toString(): String {
90+
val msg = message?.takeIf { it.isNotEmpty() } ?: ""
91+
return "${this::class.simpleName}[$severity]: $msg"
92+
}
93+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/* Brno University of Technology
2+
* Faculty of Information Technology
3+
*
4+
* BSc Thesis 2006/2007
5+
*
6+
* Railway Interlocking Simulator
7+
*
8+
* Bedrich Hovorka
9+
*/
10+
package cz.vutbr.fit.interlockSim.exceptions
11+
12+
/**
13+
* Utility functions for validation and requirement checking.
14+
* These functions replace assert() calls and if-throw boilerplate.
15+
* They throw appropriate exceptions with meaningful messages.
16+
*/
17+
18+
/**
19+
* Requires that the given value is true for simulation logic.
20+
* Throws SimulationException if the value is false.
21+
*
22+
* @param value The boolean value to check
23+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
24+
* @throws cz.vutbr.fit.interlockSim.sim.SimulationException if value is false
25+
*/
26+
inline fun requireSimulation(value: Boolean, lazyMessage: () -> String = { "Simulation requirement failed" }) {
27+
if (!value) {
28+
throw cz.vutbr.fit.interlockSim.sim.SimulationException(lazyMessage())
29+
}
30+
}
31+
32+
/**
33+
* Requires that the given value is true for simulation logic.
34+
* Throws SimulationException with specified severity if the value is false.
35+
*
36+
* @param value The boolean value to check
37+
* @param severity Severity level of the exception
38+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
39+
* @throws cz.vutbr.fit.interlockSim.sim.SimulationException if value is false
40+
*/
41+
inline fun requireSimulation(
42+
value: Boolean,
43+
severity: Severity,
44+
lazyMessage: () -> String = { "Simulation requirement failed" }
45+
) {
46+
if (!value) {
47+
throw cz.vutbr.fit.interlockSim.sim.SimulationException(severity, lazyMessage(), null, null)
48+
}
49+
}
50+
51+
/**
52+
* Requires that the given value is not null for simulation logic.
53+
* Throws SimulationException if the value is null.
54+
*
55+
* @param value The value to check
56+
* @param lazyMessage A function producing the error message (only evaluated if value is null)
57+
* @return The non-null value
58+
* @throws cz.vutbr.fit.interlockSim.sim.SimulationException if value is null
59+
*/
60+
inline fun <T : Any> requireSimulationNotNull(
61+
value: T?,
62+
lazyMessage: () -> String = { "Required value was null" }
63+
): T {
64+
if (value == null) {
65+
throw cz.vutbr.fit.interlockSim.sim.SimulationException(lazyMessage())
66+
}
67+
return value
68+
}
69+
70+
/**
71+
* Requires that the given state is valid for simulation logic.
72+
* Throws SimulationException if the value is false.
73+
*
74+
* @param value The boolean value to check
75+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
76+
* @throws cz.vutbr.fit.interlockSim.sim.SimulationException if value is false
77+
*/
78+
inline fun requireSimulationState(value: Boolean, lazyMessage: () -> String = { "Invalid simulation state" }) {
79+
if (!value) {
80+
throw cz.vutbr.fit.interlockSim.sim.SimulationException(lazyMessage())
81+
}
82+
}
83+
84+
/**
85+
* Requires that the given value is true for editor operations.
86+
* Throws EditorException if the value is false.
87+
*
88+
* @param value The boolean value to check
89+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
90+
* @throws EditorException if value is false
91+
*/
92+
inline fun requireEditor(value: Boolean, lazyMessage: () -> String = { "Editor requirement failed" }) {
93+
if (!value) {
94+
throw EditorException(lazyMessage())
95+
}
96+
}
97+
98+
/**
99+
* Requires that the given value is true for editor operations.
100+
* Throws EditorException with specified severity if the value is false.
101+
*
102+
* @param value The boolean value to check
103+
* @param severity Severity level of the exception
104+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
105+
* @throws EditorException if value is false
106+
*/
107+
inline fun requireEditor(value: Boolean, severity: Severity, lazyMessage: () -> String = { "Editor requirement failed" }) {
108+
if (!value) {
109+
throw EditorException(severity, lazyMessage())
110+
}
111+
}
112+
113+
/**
114+
* Requires that the given value is not null for editor operations.
115+
* Throws EditorException if the value is null.
116+
*
117+
* @param value The value to check
118+
* @param lazyMessage A function producing the error message (only evaluated if value is null)
119+
* @return The non-null value
120+
* @throws EditorException if value is null
121+
*/
122+
inline fun <T : Any> requireEditorNotNull(value: T?, lazyMessage: () -> String = { "Required value was null" }): T {
123+
if (value == null) {
124+
throw EditorException(lazyMessage())
125+
}
126+
return value
127+
}
128+
129+
/**
130+
* Requires that the given argument is valid.
131+
* Throws IllegalArgumentException if the value is false.
132+
*
133+
* @param value The boolean value to check
134+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
135+
* @throws IllegalArgumentException if value is false
136+
*/
137+
inline fun requireValidArgument(value: Boolean, lazyMessage: () -> String = { "Invalid argument" }) {
138+
if (!value) {
139+
throw IllegalArgumentException(lazyMessage())
140+
}
141+
}
142+
143+
/**
144+
* Requires that the given state is valid.
145+
* Throws IllegalStateException if the value is false.
146+
*
147+
* @param value The boolean value to check
148+
* @param lazyMessage A function producing the error message (only evaluated if value is false)
149+
* @throws IllegalStateException if value is false
150+
*/
151+
inline fun requireValidState(value: Boolean, lazyMessage: () -> String = { "Invalid state" }) {
152+
if (!value) {
153+
throw IllegalStateException(lazyMessage())
154+
}
155+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* Brno University of Technology
2+
* Faculty of Information Technology
3+
*
4+
* BSc Thesis 2006/2007
5+
*
6+
* Railway Interlocking Simulator
7+
*
8+
* Bedrich Hovorka
9+
*/
10+
package cz.vutbr.fit.interlockSim.exceptions
11+
12+
/**
13+
* Severity level for exceptions in the interlocking simulator
14+
*
15+
* Defines how critical an exception is and how the application should respond:
16+
* - FATAL: Must end operation immediately (simulation or editor)
17+
* - ERROR: Can be recovered by user decision, but should be handled ASAP
18+
* - WARN: Can be fixed by user decision later, non-critical
19+
*/
20+
enum class Severity {
21+
/**
22+
* Fatal error - must terminate operation immediately
23+
*/
24+
FATAL,
25+
26+
/**
27+
* Error - can be recovered by user decision but requires immediate attention
28+
*/
29+
ERROR,
30+
31+
/**
32+
* Warning - can be fixed by user decision later
33+
*/
34+
WARN
35+
}

src/main/kotlin/cz/vutbr/fit/interlockSim/sim/SimulationException.kt

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,65 @@
99
*/
1010
package cz.vutbr.fit.interlockSim.sim
1111

12+
import cz.vutbr.fit.interlockSim.exceptions.Severity
1213
import jDisco.Process
1314

1415
/**
16+
* Exception thrown during simulation - at start, between start and end of simulation.
1517
*
18+
* @property severity Severity level of the exception
1619
*/
1720
open class SimulationException : Exception {
21+
val severity: Severity
1822
private val obj: Any?
1923
private val time: Double
2024

2125
/**
22-
*
26+
* Create SimulationException with default FATAL severity
2327
*/
24-
constructor() : this(null as Any?)
28+
constructor() : this(Severity.FATAL, null as Any?)
2529

2630
/**
27-
* @param object
28-
*
31+
* Create SimulationException with default FATAL severity
32+
* @param obj Object associated with the exception
2933
*/
30-
constructor(obj: Any?) : this("", obj)
34+
constructor(obj: Any?) : this(Severity.FATAL, "", obj)
3135

3236
/**
33-
* @param message
37+
* Create SimulationException with default FATAL severity
38+
* @param message Error message
3439
*/
35-
constructor(message: String) : this(message, null as Any?)
40+
constructor(message: String) : this(Severity.FATAL, message, null as Any?)
3641

3742
/**
38-
* @param message
39-
* @param object
43+
* Create SimulationException with default FATAL severity
44+
* @param message Error message
45+
* @param obj Object associated with the exception
4046
*/
41-
constructor(message: String, obj: Any?) : this(message, null as Throwable?, obj)
47+
constructor(message: String, obj: Any?) : this(Severity.FATAL, message, null as Throwable?, obj)
4248

4349
/**
44-
* @param cause
50+
* Create SimulationException with default FATAL severity
51+
* @param cause Underlying cause
4552
*/
46-
constructor(cause: Throwable?) : this(cause, null as Any?)
53+
constructor(cause: Throwable?) : this(Severity.FATAL, cause, null as Any?)
4754

4855
/**
49-
* @param cause
50-
* @param object
56+
* Create SimulationException with default FATAL severity
57+
* @param cause Underlying cause
58+
* @param obj Object associated with the exception
5159
*/
52-
constructor(cause: Throwable?, obj: Any?) : this("", cause, obj)
60+
constructor(cause: Throwable?, obj: Any?) : this(Severity.FATAL, "", cause, obj)
5361

5462
/**
55-
* @param message
56-
* @param cause
57-
* @param object
63+
* Create SimulationException with specified severity
64+
* @param severity Severity level
65+
* @param message Error message
66+
* @param cause Underlying cause
67+
* @param obj Object associated with the exception
5868
*/
59-
constructor(message: String, cause: Throwable?, obj: Any?) : super(message, cause) {
69+
constructor(severity: Severity, message: String, cause: Throwable?, obj: Any?) : super(message, cause) {
70+
this.severity = severity
6071
this.obj = obj
6172
this.time = Process.time()
6273
}
@@ -73,6 +84,6 @@ open class SimulationException : Exception {
7384

7485
override fun toString(): String {
7586
val msg = message?.takeIf { it.isNotEmpty() } ?: ""
76-
return "${this::class.simpleName}: $msg at time $time"
87+
return "${this::class.simpleName}[$severity]: $msg at time $time"
7788
}
7889
}

0 commit comments

Comments
 (0)