@@ -62,9 +62,7 @@ public final void initialize() {
6262 if (getView () instanceof AbstractView <?>) {
6363 ((AbstractComponentView <?>) getView ()).initialize ();
6464 }
65- if (this .history != null ) {
66- restoreHistory ();
67- }
65+ applyOrRestoreHistory ();
6866 descriptor .setState (ComponentState .INITIALIZED );
6967 logger .debug ("{} Initialized the component" , getDescriptor ().getLogPrefix ());
7068 // post-initialization
@@ -85,9 +83,7 @@ public final void deinitialize() {
8583 preDeinitialize ();
8684 // deinitialization
8785 descriptor .setState (ComponentState .DEINITIALIZING );
88- if (this .history != null ) {
89- saveHistory ();
90- }
86+ saveHistory ();
9187 if (getView () instanceof AbstractView <?>) {
9288 ((AbstractComponentView <?>) getView ()).deinitialize ();
9389 }
@@ -148,25 +144,23 @@ protected void setHistoryProvider(@Nullable HistoryProvider<? extends AbstractCo
148144 return history ;
149145 }
150146
151- protected final void restoreHistory () {
152- var policy = getHistoryPolicy ();
153- logger .debug ("{} History policy during restore: {}" , getDescriptor ().getLogPrefix (), policy );
154- if (policy != NONE && history != null ) {
155- if (history .isNew ()) {
156- logger .debug ("{} History is new. Skipping restoration" , getDescriptor ().getLogPrefix ());
157- } else {
158- switch (policy ) {
159- case DATA -> restoreData ();
160- case APPEARANCE -> restoreAppearance ();
161- case ALL -> {
162- restoreData ();
163- restoreAppearance ();
164- }
165- default -> throw new AssertionError ();
166- }
167- }
168- }
169- }
147+ /**
148+ * Applies default values for the component's persistent data.
149+ * <p>
150+ * This method is invoked when no previously persisted data is available or when the current {@link HistoryPolicy}
151+ * does not include {@code DATA}. Implementations should assign meaningful default values to all data that
152+ * participates in the history mechanism.
153+ */
154+ protected void applyData () { }
155+
156+ /**
157+ * Applies default values for the component's persistent appearance state.
158+ * <p>
159+ * This method is invoked when no previously persisted appearance state is available or when the current
160+ * {@link HistoryPolicy} does not include {@code APPEARANCE}. Implementations should initialize all
161+ * appearance-related state that is managed through the history mechanism.
162+ */
163+ protected void applyAppearance () { }
170164
171165 /**
172166 * Method copies all data from history to view. This method is called at the beginning of initialization
@@ -182,49 +176,119 @@ protected void restoreData() { }
182176 */
183177 protected void restoreAppearance () { }
184178
185- protected final void saveHistory () {
186- var policy = getHistoryPolicy ();
187- logger .debug ("{} History policy during save: {}" , getDescriptor ().getLogPrefix (), policy );
188- switch (policy ) {
189- case DATA -> saveData ();
190- case APPEARANCE -> saveAppearance ();
191- case ALL -> {
192- saveData ();
193- saveAppearance ();
194- }
195- case NONE -> { }
196- default -> throw new AssertionError ();
197- }
198- }
199-
200179 /**
201180 * Method copies all data from view to history. This method is called at the beginning of deinitialization
202181 * when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#DATA}.
203182 *
204183 */
205- protected void saveData () {
206- if (this .history != null ) {
207- this .history .setNew (false );
208- }
209- }
184+ protected void saveData () { }
210185
211186 /**
212187 * Method copies all data from view to history. This method is called at the beginning of deinitialization
213188 * when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#APPEARANCE}.
214189 *
215190 */
216- protected void saveAppearance () {
217- if (this .history != null ) {
218- this .history .setNew (false );
219- }
220- }
191+ protected void saveAppearance () { }
221192
222193 protected abstract Descriptor createDescriptor ();
223194
224- void prepareHistory () {
195+ private void prepareHistory () {
225196 if (this .historyProvider != null ) {
226197 this .history = this .historyProvider .provide ();
227198 this .historyProvider = null ;
228199 }
229200 }
201+
202+ /**
203+ * Resolves the component's persistent state by either restoring it from history or applying default values when
204+ * necessary.
205+ * <p>
206+ * The component state is divided into two categories:
207+ * <ul>
208+ * <li><b>Persistent state</b> — participates in the history mechanism and can be restored or saved across
209+ * component lifecycles.</li>
210+ * <li><b>Transient state</b> — does not participate in the history mechanism and exists only at runtime.</li>
211+ * </ul>
212+ * <p>
213+ * This method operates exclusively on the <b>persistent state</b>. It does not initialize or modify transient data.
214+ * <p>
215+ * Behavior depends on the {@link HistoryPolicy} and the state of the history:
216+ * <ul>
217+ * <li>If history is new or unavailable, default values are applied via {@link #applyData()} and
218+ * {@link #applyAppearance()}.</li>
219+ * <li>If history exists, the state is selectively restored via {@link #restoreData()} and/or
220+ * {@link #restoreAppearance()}, while missing parts are filled with defaults.</li>
221+ * </ul>
222+ */
223+ private void applyOrRestoreHistory () {
224+ logger .debug ("{} History policy during initialization: {}" , getDescriptor ().getLogPrefix (), historyPolicy );
225+ if (historyPolicy == NONE || history == null || history .isNew ()) {
226+ applyData ();
227+ applyAppearance ();
228+ logger .debug ("{} Data and appearance set to defaults. Reason: {}" , getDescriptor ().getLogPrefix (),
229+ historyPolicy == NONE ? "policy is NONE" : history == null ? "history is null" : "history is new" );
230+ } else {
231+ switch (historyPolicy ) {
232+ case DATA -> {
233+ restoreData ();
234+ applyAppearance ();
235+ logger .debug ("{} Data restored from history, appearance set to defaults" ,
236+ getDescriptor ().getLogPrefix ());
237+ }
238+ case APPEARANCE -> {
239+ applyData ();
240+ restoreAppearance ();
241+ logger .debug ("{} Data set to defaults, appearance restored from history" ,
242+ getDescriptor ().getLogPrefix ());
243+ }
244+ case ALL -> {
245+ restoreData ();
246+ restoreAppearance ();
247+ logger .debug ("{} Data and appearance restored from history" , getDescriptor ().getLogPrefix ());
248+ }
249+ default -> throw new AssertionError ();
250+ }
251+ }
252+ }
253+
254+ /**
255+ * Saves the current persistent state of the component into its history.
256+ * <p>
257+ * The component state is conceptually divided into two categories:
258+ * <ul>
259+ * <li><b>Persistent state</b> — data that is stored in and restored from history
260+ * (e.g., user input, UI state, configuration).</li>
261+ * <li><b>Transient state</b> — runtime-only data that is not persisted and
262+ * exists only for the duration of the component's lifecycle.</li>
263+ * </ul>
264+ * <p>
265+ * This method operates exclusively on the <b>persistent state</b>. Transient state is not affected and must be
266+ * managed independently.
267+ * <p>
268+ * Depending on the {@link HistoryPolicy}, this method delegates to {@link #saveData()} and/or
269+ * {@link #saveAppearance()}.
270+ */
271+ private void saveHistory () {
272+ if (this .history == null ) {
273+ return ;
274+ }
275+ logger .debug ("{} History policy during deinitialization: {}" , getDescriptor ().getLogPrefix (), historyPolicy );
276+ switch (historyPolicy ) {
277+ case DATA -> {
278+ saveData ();
279+ this .history .setNew (false );
280+ }
281+ case APPEARANCE -> {
282+ saveAppearance ();
283+ this .history .setNew (false );
284+ }
285+ case ALL -> {
286+ saveData ();
287+ saveAppearance ();
288+ this .history .setNew (false );
289+ }
290+ case NONE -> { }
291+ default -> throw new AssertionError ();
292+ }
293+ }
230294}
0 commit comments